examples/SysLibs/EUserHLExample/src/euserhlexample.cpp

00001 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
00002 // All rights reserved.
00003 // This component and the accompanying materials are made available
00004 // under the terms of "Eclipse Public License v1.0"
00005 // which accompanies this distribution, and is available
00006 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
00007 //
00008 // Initial Contributors:
00009 // Nokia Corporation - initial contribution.
00010 //
00011 // Contributors:
00012 //
00013 // Description:
00014 //
00015 
00016 #include <f32file.h>
00017 #include <e32cons.h>
00018 #include <euserhl.h>
00019 
00020 
00021 _LIT(KTxtExample,"EUsableExample\n");
00022 _LIT(KTxtPressAnyKeyToContinue,"Press any key to continue\n");
00023 
00024 CConsoleBase* gConsole;
00025 
00032 _LIT(KPath, "c:\\a\\b\\c");
00033 _LIT(KOne, "One ");
00034 _LIT(KTwo, "Two ");
00035 _LIT(KTesting, "Testing ");
00036 
00037 void MaybeLeave()
00038         {
00039         // Some code that may leave
00040         }
00041 
00042 HBufC* AllocateNameL(const TDesC& aDes)
00043         {
00044         return aDes.AllocL();
00045         }
00046 
00047 void GetCurrentPath(TDes& aDes)
00048         {
00049         aDes = KPath;
00050         }
00051 
00052 void GetCurrentPathString(LString& aString)
00053         {
00054         aString = KPath; // Will auto-grow if necessary, may leave
00055         }
00056 
00057 LString AppendCurrentPathStringL(LString aString)
00058         {
00059         /*
00060         This method accepts and returns LStrings by value. It works but
00061         is not recommended due to the inherent inefficiencies.
00062         */
00063         LString result(aString);
00064         result += KPath;
00065         return result;
00066         }
00067 
00068 class CTicker : public CBase
00069         {
00070 public:
00071         void Tick() { ++iTicks; }
00072         void Tock() { ++iTocks; }
00073 
00074         void Zap() { delete this; }
00075 
00076 public:
00077         TInt iTicks;
00078         TInt iTocks;
00079         };
00080 
00081 // Defines a custom pointer cleanup policy that calls the Zap member
00082 class TTickerZapStrategy
00083         {
00084 public:
00085         static void Cleanup(CTicker* aPtr)
00086                 {
00087                 /*
00088                 The general template/class scaffolding remains the same
00089                 for all custom cleanups, just this cleanup body varies
00090                 */
00091                 aPtr->Zap();
00092                 _LIT(KTxtPrintZapp, "Zapped CTicker\n");
00093                 gConsole->Printf(KTxtPrintZapp);
00094                 }
00095         };
00096 
00097 void RegisterTicker(CTicker& aTicker)
00098         {
00099         (void)aTicker;
00100         }
00101 
00102 void RegisterTickerPtr(CTicker* aTicker)
00103         {
00104         (void)aTicker;
00105         }
00106 
00107 void TakeTickerOwnership(CTicker* aTicker)
00108         {
00109         delete aTicker;
00110         }
00111 
00112 void RegisterTimer(RTimer& aTimer)
00113         {
00114         (void)aTimer;
00115         }
00116 
00117 // Defines a custom handle cleanup policy that calls Cancel() then Close()
00118 class TCancelClose
00119         {
00120 public:
00121         template <class T>
00122         static void Cleanup(T* aHandle)
00123                 {
00124                 /*
00125                 The general template/class scaffolding remains the same
00126                 for all custom cleanups, just this cleanup body varies
00127                 */
00128                 aHandle->Cancel();
00129                 aHandle->Close();
00130                 _LIT(KTxtCancel,"Cancel Closed RTimer\n");
00131                 gConsole->Printf(KTxtCancel);
00132                 }
00133         };
00134 
00135 void BespokeCleanupFunction(TAny* /*aData*/)
00136         {
00137         _LIT(KTxtCleanup,"BespokeCleanupFunction\n");
00138         gConsole->Printf(KTxtCleanup);
00139         }
00140 
00141 // The walkthroughs themselves
00142 
00149 class CStringUserTwoPhase : public CBase
00150         {
00151 public:
00152         static CStringUserTwoPhase* NewL(const TDesC& aName)
00153                 {
00154                 /*
00155                 We can use the resource management utility classes in
00156                 two-phase if we want.
00157                 */
00158                 LCleanedupPtr<CStringUserTwoPhase> self(new(ELeave) CStringUserTwoPhase);
00159                 self->Construct(aName);
00160                 /*
00161                 Calling Unmanage() disables cleanup and yields the
00162                 previously managed pointer so that it can be safely
00163                 returned
00164                 */
00165                 return self.Unmanage(); 
00166                 }
00167 
00168         virtual void Construct(const TDesC& aName)
00169                 {
00170                 /*
00171                 This assignment may leave if LString fails to allocate a
00172                 heap buffer large enough to hold the data in aName
00173                 */
00174                 iName = aName; 
00175                 }
00176 
00177         ~CStringUserTwoPhase()
00178                 {
00179                 // The iName LString cleans up after itself automatically 
00180                 }
00181 
00182         const TDesC& Name() 
00183                 {
00184                 // We can just return an LString directly as a const TDesC
00185                 return iName; 
00186                 }
00187 
00188 protected:
00189         CStringUserTwoPhase()
00190                 {
00191                 /*
00192                 Everything interesting happens in ConstructL in this
00193                 version. 
00194 
00195                 Default initialization of the iName LString does not
00196                 allocate a heap buffer, and so cannot leave. As long as
00197                 initialization is deferred to ConstructL, LStrings can be
00198                 used safely with two-phase construction.
00199                 */
00200                 }
00201 
00202 protected:
00203         LString iName;
00204         };
00205 
00217 class CStringUserSinglePhase : public CBase
00218         {
00219 public:
00220         /*
00221         This macro is necessary to ensure cleanup is correctly handled
00222         in the event that a constructor may leave beneath a call to
00223         new(ELeave)
00224         */
00225         CONSTRUCTORS_MAY_LEAVE
00226 
00227         static CStringUserSinglePhase* NewL(const TDesC& aName)
00228                 {
00229                 return new(ELeave) CStringUserSinglePhase(aName);
00230                 }
00231 
00232         ~CStringUserSinglePhase()
00233                 {
00234                 // The iName LString cleans up after itself automatically
00235                 }
00236 
00237         const TDesC& Name() 
00238                 {
00239                 // We can just return an LString directly as a const TDesC
00240                 return iName;
00241                 }
00242 
00243 protected:
00244         CStringUserSinglePhase(const TDesC& aName)
00245                 /*
00246                 This initialization of iName may leave because LString
00247                 needs to allocate a heap buffer to copy the aName string
00248                 data into
00249                 */
00250                 : iName(aName) 
00251                 {
00252                 /*
00253                 If iName initialization is successful but the constructor
00254                 then goes on to leave later, iName (like all fields fully
00255                 constructed at the point of a leave in a constructor) will
00256                 be destructed, and so clean up after itself
00257                 */
00258                 MaybeLeave();
00259                 }
00260 
00261 protected:
00262         LString iName;
00263         };
00264 
00265 
00266 void WalkthroughStringsL()
00267         {
00268         _LIT(KTxtOption1,"Option1: String handling using EUser high level library\n");
00269     gConsole->Printf(KTxtOption1);
00270     _LIT(KTxtFormatString,"String %d");
00271     _LIT(KTxtPrintString,"String %d = %S\n");
00272        {
00273                 // Trivially exercise the LString using classes defined above
00274 
00275                 LCleanedupPtr<CStringUserTwoPhase> one(CStringUserTwoPhase::NewL(KOne));
00276                 _LIT(KTxtSinglePhaseConstructor,"Single phase name: %S\n");
00277                 gConsole->Printf(KTxtSinglePhaseConstructor, &one->Name());
00278 
00279                 LCleanedupPtr<CStringUserSinglePhase> two(CStringUserSinglePhase::NewL(KTwo));
00280                 _LIT(KTxtTwoPhaseConstructor,"Single phase name: %S\n");
00281                 gConsole->Printf(KTxtTwoPhaseConstructor, &two->Name());
00282 
00283                 gConsole->Printf(KTxtPressAnyKeyToContinue);
00284                 gConsole->Getch();
00285                 // Both instances are automatically deleted as we go out of scope
00286                 }
00287 
00288                 {
00289                 /*
00290                 A default constructed LString starts empty, doesn't
00291                 allocate any memory on the heap, and therefore the
00292                 following cannot leave
00293                 */
00294                 LString s;
00295 
00296                 /*
00297                 But it will grow on demand if you assign to it, so it has
00298                 enough space to hold the copied string data, and so
00299                 assignment may leave
00300                 */
00301                 s = KOne;
00302 
00303                 /*
00304                 Similarly if you append to it with the leaving variant of
00305                 Append(), AppendL(), if may grow on demand
00306                 */
00307                 s.AppendL(KTwo);
00308 
00309                 // The += operator for LString also maps to AppendL()
00310                 _LIT(KThree, "Three ");
00311                 s += KThree;
00312 
00313                 /*
00314                 You can also use new leaving format methods that also grow
00315                 on demand
00316                 */
00317                 s.AppendFormatL(KTesting);
00318 
00319                 /*
00320                 This general style of use of LString may be preferable to
00321                 typical descriptor use for a number of reasons e.g. it
00322                 avoids the common temptation to set an artificial maximum
00323                 buffer size; it avoids massive conservative over-allocation
00324                 when the average case length of a string is far less than
00325                 the worst-case maximum; it will not surprise you (compared
00326                 to the alternative of a large stack-allocated TBuf) by
00327                 triggering stack overflow.
00328                 */
00329 
00330                 // An LString can be printed the same way as any descriptor
00331                 _LIT(KTxtValue,"Value: %S\n");
00332                 gConsole->Printf(KTxtValue, &s);
00333 
00334                 // An LString can be compared the same way as any descriptor
00335                 _LIT(KTxtLStringCompare," Comparing LString with a literal is successful\n");
00336                 _LIT(KPhrase, "One Two Three Testing ");
00337                 if(s == KPhrase)
00338                         {
00339                         gConsole->Printf(KTxtLStringCompare);
00340                         }
00341 
00342                 // An LString supports all TDesC and TDes methods
00343                 _LIT(KTxtLStringSupportedAPI1,"LString supports TDesC and TDes methods\n");
00344                 if(s.Find(KTwo) == 4)
00345                         {
00346                         gConsole->Printf(KTxtLStringSupportedAPI1);     
00347                         }
00348                 // An LString supports all TDesC and TDes operators
00349                 _LIT(KTxtLStringSupportedAPI2,"LString supports TDesC and TDes operators\n");
00350                 if(s[4] == TChar('T'))
00351                         {
00352                         gConsole->Printf(KTxtLStringSupportedAPI2);
00353                         }
00354                 TInt untrimmed = s.Length();
00355                 s.Trim();
00356                 if(s.Length() == untrimmed - 1)
00357                         {
00358                         //LString supports Trim API
00359                         }
00360 
00361                 s.UpperCase();
00362                 _LIT(KTxtPrintUpperCase,"UpperCase: %S\n");
00363                 gConsole->Printf(KTxtPrintUpperCase, &s);
00364                 s.LowerCase();
00365                 _LIT(KTxtPrintLowerCase,"UpperCase: %S\n");
00366                 gConsole->Printf(KTxtPrintLowerCase, &s);
00367                 gConsole->Printf(KTxtPressAnyKeyToContinue);
00368                 gConsole->Getch();
00369                 /*
00370                 The underlying heap allocated buffer is released
00371                 automatically when the LString goes out of scope, either
00372                 normally or through a leave
00373                 */
00374                 }
00375 
00376                 {
00377                 // You can initialize with a MaxLength value
00378                 LString s(KMaxFileName); // This operation may leave
00379                 if(s.MaxLength() == KMaxFileName)
00380                         {       
00381                         //LString supports MaxLength API
00382                         }
00383 
00384                 /*
00385                 And you can dynamically adjust MaxLength later using 
00386                 SetMaxLengthL() if you want an exact allocated size.
00387                 Setting MaxLength() on construction or via SetMaxLengthL() is
00388                 exact; calling MaxLength() immediately afterwards is
00389                 guaranteed to return exactly the value you specified.
00390                 */
00391                 s.SetMaxLengthL(2 * KMaxFileName);
00392                 if(s.MaxLength() == 2 * KMaxFileName)
00393                         {
00394                         //MaxLength is successfully adjusted.
00395                         }
00396 
00397                 /*
00398                 Pre-setting MaxLength is important when passing an LString
00399                 as a TDes to a library function, because the LString can't
00400                 be auto-grown via the TDes API.
00401                 */
00402 
00403                 }
00404 
00405                 {
00406                 /*
00407                 You can initialize from any descriptor (or literal) and the
00408                 string data is copied into the LString
00409                 */
00410                 LString s(KOne); // From a literal
00411                 s += KTwo;
00412                 LString half(s.Left(s.Length() / 2)); // Left returns a TPtrC
00413                 _LIT(KTxtPrintAllandHalf,"All: %S, Half: %S\n");
00414                 gConsole->Printf(KTxtPrintAllandHalf, &s, &half);
00415 
00416                 /*
00417                 On the other hand, you can initialize from a returned
00418                 HBufC* and the LString automatically takes ownership
00419                 */
00420                 LString own(AllocateNameL(KTesting));
00421                 _LIT(KTxtOwnedString,"What I own: %S\n");
00422                 gConsole->Printf(KTxtOwnedString, &own);
00423 
00424                 /*
00425                 Following that you can re-assign an HBufC to an existing
00426                 string using the assignment operator 
00427                 taking ownership of the new content. 
00428                 */
00429                 own = AllocateNameL(KTesting);
00430                 
00431                 /*
00432                 Following that you can re-assign an HBufC to an existing
00433                 string. The string destroys its original content before
00434                 taking ownership of the new content. 
00435                 */
00436                 own.Assign(AllocateNameL(KTesting));
00437                 
00438                 /*
00439                 The content of one string can similarly be assigned
00440                 to another to avoid copying. In this example, the content 
00441                 is detached from 's' and transfered to 'own'.
00442                 */  
00443                 own.Assign(s);
00444                 
00445                 /*
00446                 The same content transfer can be achieved from an RBuf to a
00447                 string. You may need to do this if a legacy method returns
00448                 you an RBuf. The RBuf is emptied of its content.
00449                 */
00450                 RBuf16 buf;
00451                 buf.CreateL(KOne);
00452                 own.Assign(buf);
00453         
00454                 /*
00455                 You can also assign a simple text array to a string as its
00456                 new buffer. This method initialises the length to zero.
00457                 */   
00458                 own.Assign((TText*)User::Alloc(24*(TInt)sizeof(TText)), 24);
00459                 
00460                 /*
00461                 If the buffer has already been filled with some characters
00462                 then you supply the length in this alternative Assign() method.
00463                 */   
00464                 own.Assign((TText*)User::Alloc(24*(TInt)sizeof(TText)), 12,24);
00465                 gConsole->Printf(KTxtPressAnyKeyToContinue);
00466                 gConsole->Getch();
00467                 /*
00468                 Each Assign() destroys the old content before assuming ownership
00469                 of the new.
00470                 As usual the last content of the string is destroyed when the 
00471                 LString goes out of scope
00472                 */
00473                 }
00474 
00475                 {
00476                 /*
00477                 You can reserve extra free space in preparation for an 
00478                 operation that adds characters to the string. You may
00479                 need to do this when you cannot use any of the auto-buffer
00480                 extending LString methods to achieve your objective.
00481                 */
00482                 LString s(KOne);
00483                 s.ReserveFreeCapacityL(4);
00484                 if(s.Length() == 4)
00485                         {
00486                         //Length() API gives the current length of the string
00487                         }
00488                 if(s.MaxLength() >= 8)
00489                         {
00490                         //MaxLength() gives the maximum length supported by the string
00491                         }
00492 
00493                 /*
00494                 Almost all the methods that may extend the string buffer,
00495                 including the explicit ReserveFreeCapacityL(), but excluding
00496                 SetMaxLengthL(), attempt to grow the size exponentially. 
00497                 The exponential growth pattern is expected to give better 
00498                 performance at an amortised complexity of O(n) when adding n characters.
00499                 If the exponential growth is less than the supplied extra size
00500                 then the supplied size is used instead to save time.
00501                 The exponential growth is used in anticipation of further additions
00502                 to a string. This trades-off speed efficiency for space efficiency.
00503                 If required you may be able to swap the oversized buffer for 
00504                 a more compact one using:
00505                 */
00506                 s.Compress();
00507                 if(s.MaxLength() >= 4)
00508                         {
00509                         //Compress() API is used to compress the unused memory.
00510                         }
00511                     
00512                 /*
00513                 Resize() attempts to re-allocate a smaller buffer to copy
00514                 the content into. If the new memory cannot be allocated then the
00515                 original string is left unaffected. 
00516                 
00517                 When you have finished using the content of a string you can
00518                 get its buffer released without destroying the string itself. 
00519                 You may want to do this when using member declared strings.
00520                 Automatic strings are destroyed when they go out of scope.
00521                 */
00522                 s.Reset();
00523                 if(s.Length() == 0)
00524                         {
00525                         //Buffer of the string is released, hence length is zero.
00526                         }
00527                 if(s.MaxLength() == 0)
00528                         {
00529                         //Buffer of the string is released, hence maximum length is zero.
00530                         }
00531                 
00532                 }
00533 
00534                 {
00535                 /*
00536                 An LString can be passed directly to any function requiring
00537                 a const TDesC&
00538                 */
00539                 TInt year = 2009;
00540 
00541                 LString s;
00542                 _LIT(KTxtFormatYear1,"Happy New Year %d");
00543                 s.FormatL(KTxtFormatYear1, year);
00544                 // InfoPrint() takes a const TDesC&
00545                 User::InfoPrint(s);
00546 
00547                 LString pattern;
00548                 _LIT(KTxtFormatYear2,"*Year %d");
00549                 pattern.FormatL(KTxtFormatYear2, year);
00550                 // Match() takes a const TDesC& as a pattern
00551                 TInt loc = s.Match(pattern);
00552                 if(loc == 10)
00553                         {
00554                         //Match() API is demonstrated successfully.
00555                         }
00556                 }
00557 
00558                 {
00559                 /*
00560                 An LString can be passed directly to any function requiring
00561                 a TDes& but care must always be taken to pre-set MaxLength()
00562                 since LStrings can't be automatically grown via the TDes
00563                 interface
00564                 */
00565 
00566                 LString s;
00567                 /*
00568                 Calling GetCurrentPath(s) now would panic because LStrings
00569                 are initialized by default to MaxLength 0.  Although s is
00570                 an LString GetCurrentPath() takes a TDes& and so inside the function
00571                 's' behaves as a TDes and would panic with USER 11 if the resulting 
00572                 new length of s is greater than its maximum length.
00573                 */
00574                 if(s.MaxLength() == 0)
00575                         {
00576                         //LStrings are initialized by default to MaxLength 0
00577                         }
00578 
00579                 /*
00580                 Calling SetMaxLengthL() will automatically realloc the
00581                 underlying buffer if required, and is guaranteed to leave
00582                 MaxLength() equal to the specified value
00583                 */
00584                 s.SetMaxLengthL(KMaxFileName);
00585                 GetCurrentPath(s);
00586                 _LIT(KTxtPrintPath,"Path: %S\n");
00587                 gConsole->Printf(KTxtPrintPath, &s);
00588                 if(s == KPath)
00589                         {
00590                         //String comparison is successful
00591                         }
00592 
00593                 /*
00594                 If SetMaxLengthL() adjusts MaxLength() to be lower than the current
00595                 Length(), the data is truncated to the new MaxLength() and
00596                 Length() set to the new MaxLength().
00597                 */
00598                 s.SetMaxLengthL(s.Length() / 2);
00599                 _LIT(KTxtTruncatedPath,"Truncated path: %S\n");
00600                 gConsole->Printf(KTxtTruncatedPath, &s);
00601                 if(s.Length() == s.MaxLength())
00602                         {
00603                         //String comparison is successful
00604                         }
00605 
00606                 /*
00607                 An initial MaxLength() can be specified when constructing an
00608                 LString. Note that unlike the default constructor, this
00609                 variant allocates and may leave.
00610                 */
00611                 LString s2(KMaxFileName);
00612                 GetCurrentPath(s2);
00613                 gConsole->Printf(KTxtPrintPath, &s2);
00614                 if(s2 == KPath)
00615                         {
00616                         //String comparison is successful
00617                         }
00618 
00619                 /*
00620                 Your code and APIs can benefit from LString's auto-growth
00621                 behaviour by accepting an LString to fill in as an output
00622                 parameter. Using LString rather than TDes parameters means 
00623                 that the function is able to safely increase the size of the 
00624                 string as the LString will re-allocate as necessary
00625                 */
00626                 LString s3;
00627                 // GetCurrentPathString() takes an LString&
00628                 GetCurrentPathString(s3);
00629                 gConsole->Printf(KTxtPrintPath, &s3);
00630                 if(s3 == KPath)
00631                         {
00632                         //String comparison is successful
00633                         }
00634 
00635                 /*
00636                 As a well-defined value class, if you want to, LStrings can
00637                 be passed and returned by value. This is relatively
00638                 inefficient however due to the amount of copying and heap
00639                 reallocation involved. 
00640                 */
00641                 LString s4(AppendCurrentPathStringL(s3));
00642                 _LIT(KTxtAppendedPath,"Appended path: %S\n");
00643                 gConsole->Printf(KTxtAppendedPath, &s4);
00644                 if(s4.Length() == s3.Length() * 2)
00645                         {
00646                         //String comparison is successful
00647                         }
00648                 }
00649 
00650                 {
00651                 /*
00652                 LStrings can be allocated on the heap if necessary. 
00653                 Then it can managed as part of an array of string pointers.
00654                 */
00655                 TInt n = 5;
00656                 LCleanedupHandle<RPointerArray<LString>, TResetAndDestroy> sarray;
00657                 
00658                 for (TInt i = 0; i < n; ++i) 
00659                         {
00660                         LString* s = new(ELeave) LString;
00661                         s->FormatL(KTxtFormatString, i);
00662                         sarray->Append(s);
00663                         }
00664 
00665                 for (TInt i = 0, n = sarray->Count(); i < n; ++i) 
00666                         {
00667                         LString tmp;
00668                         tmp.FormatL(KTxtFormatString, i);
00669                         if(tmp == *(*sarray)[i])
00670                                 {
00671                                 
00672                                 }
00673                         gConsole->Printf(KTxtPrintString, i, (*sarray)[i]);
00674                         }
00675 
00676                 }
00677 
00678                 {
00679                 /*
00680                 Any allocation failure in new(ELeave)LString throws
00681                 KErrNoMemory and cleans up fully after itself.
00682                 */
00683 
00684                 __UHEAP_MARK;
00685                 TRAPD(status, new(ELeave) LString(100 * 1024 * 1024));
00686                 if(status == KErrNoMemory)
00687                         {
00688                         //cleans up after itself fully, there is no need to take any further action.
00689                         }
00690                 __UHEAP_MARKEND;
00691                 }
00692 
00693                 {
00694                 /*
00695                 Native C arrays (both heap and stack allocated) of LStrings
00696                 also work, although their use is not recommended.
00697                 */
00698 
00699                 TInt n = 5;
00700                 LCleanedupArray<LString> sarray(new(ELeave) LString[n]);
00701 
00702                 for (TInt i = 0; i < n; ++i) 
00703                         {
00704                         sarray[i].FormatL(KTxtFormatString, i);
00705                         }
00706 
00707                 for (TInt i = 0; i < n; ++i) 
00708                         {
00709                         LString tmp;
00710                         tmp.FormatL(KTxtFormatString, i);
00711                         if(tmp == sarray[i])
00712                                 {
00713                                 //comparison of strings is successful
00714                                 }
00715                         gConsole->Printf(KTxtPrintString, i, &sarray[i]);
00716                         }
00717 
00718                 }
00719                 
00720         }
00721 
00727 class CManagedUserTwoPhase : public CBase
00728         {
00729 public:
00730         static CManagedUserTwoPhase* NewL(CTicker* aTicker)
00731                 {
00732                 /*
00733                 We can use the resource management utility classes in
00734                 two-phase if we want to.
00735                 */
00736                 LCleanedupPtr<CManagedUserTwoPhase> self(new(ELeave) CManagedUserTwoPhase);
00737                 self->ConstructL(aTicker);
00738                 /*
00739                 Calling Unmanage() disables cleanup and yields the
00740                 previously managed pointer so that it can be safely
00741                 returned.
00742                 */
00743                 return self.Unmanage(); 
00744                 }
00745 
00746         ~CManagedUserTwoPhase()
00747                 {
00748                 /*
00749                 The iTicker manager will automatically delete the CTicker
00750                 The iTimer manager will automatically Close() the RTimer.
00751                 */
00752                 }
00753 
00754         CTicker& Ticker()
00755                 {
00756                 // If we dereference the management object we get a CTicker&.
00757                 return *iTicker;
00758                 }
00759 
00760         RTimer& Timer()
00761                 {
00762                 // If we dereference the management object we get an RTimer&.
00763                 return *iTimer;
00764                 }
00765 
00766 private:
00767         
00768         virtual void ConstructL(CTicker* aTicker)
00769                 {
00770                 // Take ownership and manage aTicker.
00771                 iTicker = aTicker; 
00772 
00773                 // Note use of -> to indirect through the management wrapper.
00774                 iTimer->CreateLocal() OR_LEAVE; 
00775                 }
00776         
00777         CManagedUserTwoPhase()
00778                 {
00779                 /*
00780                 Everything interesting happens in ConstructL() in this
00781                 version. 
00782 
00783                 Default initialization of the iName LString does not
00784                 allocate a heap buffer, and so cannot leave. As long as
00785                 initialization is deferred to ConstructL(), LStrings can be
00786                 used safely with two-phase construction.
00787                 */
00788                 }
00789 
00790 private:
00791         // We have to use LManagedXxx for fields, not LCleanedupXxx
00792         LManagedPtr<CTicker> iTicker;
00793         LManagedHandle<RTimer> iTimer;
00794         };
00795 
00808 class CManagedUserSinglePhase : public CBase
00809         {
00810 public:
00811         /*
00812         This macro is necessary to ensure cleanup is correctly handled
00813         in the event that a constructor may leave beneath a call to
00814         new(ELeave)
00815         */
00816         CONSTRUCTORS_MAY_LEAVE
00817 
00818         static CManagedUserSinglePhase* NewL(CTicker* aTicker)
00819                 {
00820                 return new(ELeave) CManagedUserSinglePhase(aTicker);
00821                 }
00822 
00823         ~CManagedUserSinglePhase()
00824                 {
00825                 /*
00826                 The iTicker manager destructor will automatically Zap() the CTicker.
00827                 The iTimer manager destructor will automatically Close() the RTimer.
00828                 */
00829                 }
00830 
00831         CTicker& Ticker()
00832                 {
00833                 // If we dereference the management object we get a CTicker&.
00834                 return *iTicker;
00835                 }
00836 
00837         RTimer& Timer()
00838                 {
00839                 // If we dereference the management object we get an RTimer&.
00840                 return *iTimer;
00841                 }
00842 
00843 private:
00844         CManagedUserSinglePhase(CTicker* aTicker)
00845                 /*
00846                 Take ownership and manage aTicker. Note that initialization
00847                 of the LManagedXxx classes does not actually leave, but
00848                 initialization of the LCleanedupXxx classes can.
00849                 */
00850                 : iTicker(aTicker)
00851                 {
00852                 /*
00853                 If iTicker initialization is successful but the constructor
00854                 then goes on to leave later, iTicker (like all fields fully
00855                 constructed at the point of a leave in a constructor) will
00856                 be destructed, and the manager will cleanup the CTicker.
00857 
00858                 Note use of -> to indirect through the management wrapper.
00859                 */
00860                 iTimer->CreateLocal(); 
00861 
00862                 // Likewise if we leave here, both iTicker and iTimer will
00863                 // undergo managed cleanup.
00864                 MaybeLeave();
00865                 }
00866 
00867 private:
00868         // We have to use LManagedXxx for fields, not LCleanedupXxx.
00869         LManagedPtr<CTicker, TTickerZapStrategy> iTicker;
00870         LManagedHandle<RTimer> iTimer;
00871         };
00872 
00873 //Class definition of trivial R-Class
00874 class RSimple
00875         {
00876 public:
00877         
00878         RSimple(){iData = NULL;}
00879         
00880         //Open function sets value
00881         void OpenL(TInt aValue)
00882                 {
00883                 iData = new(ELeave) TInt(aValue);
00884                 }
00885         
00886         //Cleanup function – frees resource
00887         void Close()
00888                 {
00889                 delete iData;
00890                 iData = NULL;
00891                 }
00892 
00893         //Cleanup function – frees resource
00894         void Free()
00895                 {
00896                 delete iData;
00897                 iData = NULL;
00898                 }
00899 
00900         //Cleanup function – frees resource
00901         void ReleaseData()
00902                 {
00903                 delete iData;
00904                 iData = NULL;
00905                 }
00906         
00907         //static cleanup function – frees aRSimple resources
00908         static void Cleanup(TAny* aRSimple)
00909                 {
00910                 static_cast<RSimple*>(aRSimple)->Close();
00911                 }
00912 
00913 
00914 private:
00915         TInt* iData;
00916 
00917         };
00918 
00919 
00926 DEFINE_CLEANUP_FUNCTION(RSimple, ReleaseData);
00927 
00928 
00929 void WalkthroughManagedL()
00930         {
00931         _LIT(KTxtOption2,"Option2: Object creation and resource management using EUser high level library\n");
00932         gConsole->Printf(KTxtOption2);
00933                 {
00934                 // Trivially exercise the manager-using classes defined above.
00935                 CTicker* ticker1 = new(ELeave) CTicker;
00936                 LCleanedupPtr<CManagedUserTwoPhase> one(CManagedUserTwoPhase::NewL(ticker1));
00937                 if(&one->Ticker() == ticker1)
00938                         {
00939                         _LIT(KTxtLCleanedupPtrDemo1,"Creating an instance of CTicker using LCleanedupPtr\n");
00940                         gConsole->Printf(KTxtLCleanedupPtrDemo1);
00941                         }
00942                 one->Timer().Cancel(); // Just to check we can get at it
00943 
00944                 CTicker* ticker2 = new(ELeave) CTicker;
00945                 LCleanedupPtr<CManagedUserSinglePhase> two(CManagedUserSinglePhase::NewL(ticker2));
00946                 if(&two->Ticker() == ticker2)
00947                         {
00948                         _LIT(KTxtLCleanedupPtrDemo2,"Creating second instance of CTicker using LCleanedupPtr\n");
00949                         gConsole->Printf(KTxtLCleanedupPtrDemo2);
00950                         }
00951                 two->Timer().Cancel(); // Just to check we can get at it
00952         _LIT(KTxtLCleanedupPtr,"Both instances are automatically deleted as we go out of scope\n");
00953         gConsole->Printf(KTxtLCleanedupPtr);
00954         gConsole->Printf(KTxtPressAnyKeyToContinue);
00955         gConsole->Getch();
00956                 }
00957 
00958                 // Always use LCleanedupXxx for locals, not LManagedXxx
00959 
00960                 {
00961                 /*
00962                 Behind the scenes the LCleanedupXxx constructors push a
00963                 cleanup item onto the cleanup stack and so may leave. If
00964                 there is a leave during construction, the supplied pointer
00965                 will still get cleaned up.
00966                 */
00967                 LCleanedupPtr<CTicker> t(new(ELeave) CTicker);
00968 
00969                 /*
00970                 We can access CTicker's members via the management object
00971                 using ->
00972                 */
00973                 t->Tick();
00974                 t->Tock();
00975                 if(t->iTicks == t->iTocks)
00976                         {
00977                         _LIT(KTxtLCleanedupPtrDemo3,"CTicker members access using LCleanedupPtr is successful\n");
00978                         gConsole->Printf(KTxtLCleanedupPtrDemo3);
00979                         gConsole->Printf(KTxtPressAnyKeyToContinue);
00980                 gConsole->Getch();
00981                         }
00982 
00983                 /*
00984                 We can get at a reference to the managed object using *
00985                 when we need to, e.g. if we need to pass it to a function.
00986                 */
00987                 RegisterTicker(*t); // Takes a CTicker&
00988 
00989                 /*
00990                 If some unfriendly interface needs a pointer rather than a
00991                 ref, we have a couple of options.
00992                 */
00993                 RegisterTickerPtr(&*t); // Takes a CTicker*
00994                 RegisterTickerPtr(t.Get()); // Takes a CTicker*
00995 
00996                 /*
00997                 Note the use of . in t.Get() above; this distinguishes
00998                 operations on the managing type from operations on the
00999                 managed object.
01000                 
01001                 When the management object goes out of scope, either
01002                 normally or as the result of a leave, the managed object is
01003                 automatically deleted.
01004                 */
01005                 }
01006 
01007                 {
01008                 /*
01009                 Sometimes you need to protect something temporarily before
01010                 transferring ownership e.g. by returning the pointer or
01011                 passing it to a function that takes ownership.
01012                 */
01013 
01014                 LCleanedupPtr<CTicker> t(new(ELeave) CTicker);
01015 
01016                 // Protected while we do this
01017                 MaybeLeave(); 
01018 
01019                 /*
01020                 But now we want to hand it off, so we use Unmanage() to
01021                 both return a pointer and break the management link
01022                 */
01023                 TakeTickerOwnership(t.Unmanage());
01024                 
01025                 /*
01026                 Now when it goes out of scope, no cleanup action is
01027                 performed.
01028                 */
01029                 }
01030 
01031                 {
01032                 /*
01033                 If needed, it is possible to reuse a manager by using = to
01034                 assign it a new managed object.
01035                 */
01036 
01037                 // Not managing anything to start with
01038                 LCleanedupPtr<CTicker> t;
01039                 if(t.Get() == NULL)
01040                         {
01041                         //Successfully initialised to NULL
01042                         }
01043                 if(&*t == NULL)
01044                         {
01045                         //CTicker* value is also NULL
01046                         }
01047 
01048                 for (TInt i = 0; i < 10; ++i)
01049                         {
01050                         /*
01051                         If an object is already being managed, it is cleaned up
01052                         before taking ownership of the new object.
01053                         */
01054                         t = new(ELeave) CTicker;
01055                         }
01056                 /*
01057                 We're left owning the final ticker instance, all prior
01058                 instances having been automatically deleted.
01059                 */
01060                 }
01061 
01062                 {
01063                 // If you have stateful code where a pointer can sometimes be NULL.
01064                 LCleanedupPtr<CTicker> t(new(ELeave) CTicker);
01065 
01066                 // Does t refer to NULL?
01067                 if (!t)
01068                         {
01069                         _LIT(KTxtNull,"LCleanedupPtr object refers to Null\n" );
01070                         gConsole->Printf(KTxtNull);
01071                         }
01072 
01073                 t = NULL; // Also releases the currently managed CTicker 
01074 
01075                 // Does t refer to a non-NULL pointer?
01076                 if (t)
01077                         {
01078                         _LIT(KTxtNonNull,"LCleanedupPtr object refers to Non Null pointer\n" );
01079                         gConsole->Printf(KTxtNonNull);
01080                         }
01081                 }
01082 
01083                 {
01084                 // LCleanedupPtr uses delete to cleanup by default, but alternative cleanups can be specified
01085 
01086                 // We just want to free this one and not invoke the destructor
01087                 LCleanedupPtr<CTicker, TPointerFree> t(static_cast<CTicker*>(User::AllocL(sizeof(CTicker))));
01088 
01089                 // Now User::Free() is called when t goes out of scope
01090                 }
01091 
01092                 {
01093                 /*
01094                 As well as the stock options, custom cleanup policies can
01095                 also be defined. See above for the definition of
01096                 TTickerZap.
01097                 */
01098                 LCleanedupPtr<CTicker, TTickerZapStrategy> t(new(ELeave) CTicker);
01099 
01100                 // Now Zap() is called on the CTicker instance when t goes out of scope
01101                 }
01102 
01103                 {
01104                 /*
01105                 LCleanedupHandle is very similar in behaviour to
01106                 LCleanedupPtr, the main difference being that it can define
01107                 and contain its own instance of a handle rather than
01108                 being supplied one.
01109                 */
01110                 LCleanedupHandle<RTimer> t;
01111 
01112                 // Again, access to managed handle members is via ->
01113                 t->CreateLocal() OR_LEAVE;
01114                 t->Cancel();
01115 
01116                 //We can get a reference to the handle for passing to functions using *
01117                 RegisterTimer(*t);
01118 
01119                 /*
01120                 When the management object goes out of scope, either
01121                 normally or as the result of a leave, the managed object is
01122                 automatically cleanup by calling Close() on it.
01123                 */
01124                 }
01125 
01126                 {
01127                 /*
01128                 LCleanedupHandle calls Close() by default, but alternative
01129                 cleanups can be specified.
01130                 
01131                 We want this RPointerArray cleanup with with
01132                 ResetAndDestroy instead of Close().
01133                 */
01134                 LCleanedupHandle<RPointerArray<HBufC>, TResetAndDestroy> array;
01135                 for (TInt i = 0; i < 10; ++i) 
01136                         {
01137                         array->AppendL(HBufC::NewL(5));
01138                         }
01139 
01140                 //Now when array goes out of scope, ResetAndDestroy is called to clean it up.
01141                 }
01142 
01143                 {
01144                 /*
01145                 As well as the stock options, custom cleanup policies can
01146                 also be defined. See above for the definition of TCancelClose.
01147                 */
01148                 LCleanedupHandle<RTimer, TCancelClose> t;
01149                 t->CreateLocal();
01150 
01151                 // Now Cancel() followed by Close() are called when t goes out of scope
01152                 }
01153 
01154 
01155                 {
01156                 /*
01157                 LCleanedupHandleRef calls Close() by default, but alternative
01158                 cleanups can be specified.
01159                 
01160                 We want this RPointerArray cleanup with
01161                 ResetAndDestroy instead of Close().
01162                 */
01163                 RPointerArray<HBufC> rar;
01164                 // calls to functions that cannot leave here
01165                 rar.Append(HBufC::NewL(5));
01166                 rar.Append(HBufC::NewL(5));
01167 
01168 
01169                 LCleanedupRef<RPointerArray<HBufC>, TResetAndDestroy> array(rar);
01170                 // calls to functions that could leave here
01171                 for (TInt i = 0; i < 10; ++i) 
01172                         {
01173                         array->AppendL(HBufC::NewL(5));
01174                         }
01175 
01176                 // Now when array goes out of scope, ResetAndDestroy is called to clean it up
01177                 }
01178 
01179                 {
01180                 /*
01181                 Never mix direct cleanup stack API calls with management
01182                 class use within the same function, because their
01183                 interaction can be confusing and counter-intuitive. Avoid
01184                 the use of LC methods that leave objects on the cleanup
01185                 stack, and use L methods instead.
01186 
01187                 If a badly-behaved API were to offer only an LC variant,
01188                 you would have to use it as follows
01189                 */
01190                 HBufC* raw = HBufC::NewLC(5);
01191                 // Must pop immediately to balance the cleanup stack, before instantiating the manager
01192                 CleanupStack::Pop(); 
01193                 LCleanedupPtr<HBufC> wrapped(raw);
01194 
01195                 /*
01196                 Never do this:
01197                 LCleanedupPtr<HBufC> buf(HBufC::NewLC(5));
01198                 CleanupStack::Pop();
01199                 because the manager will be popped (having been pushed
01200                 last), not the raw buf pointer as you might have hoped
01201 
01202                 A cleaner alternative may be to write your own L function
01203                 wrapper around the LC function supplied.
01204 
01205                 Luckily this situation (an LC method without a
01206                 corresponding L method) is rare in practice.
01207                 */
01208                 }
01209 
01210                 {
01211                 // Although rarely used on the Symbian platform, C++ arrays are supported with a custom management class
01212                 LCleanedupArray<CTicker> array(new CTicker[5]);
01213 
01214                 // The array is cleaned up with delete[] on scope exit
01215                 }
01216 
01217                 {
01218                 /*
01219                 Although most cases are best covered by applying custom
01220                 cleanup policies to the management classes already
01221                 described, there is also a general TCleanupItem style
01222                 cleanup option.
01223                 */
01224                 TAny* data = NULL; // But could be anything
01225                 LCleanedupGuard guard1(BespokeCleanupFunction, data);
01226                 // On scope exit BespokeCleanupFunction() is called on data.
01227 
01228                 LCleanedupGuard guard2(BespokeCleanupFunction, data);
01229                 // But cleanup can also be disabled in this case, as follows:
01230                 guard2.Dismiss();
01231                 }
01232                 
01233                 {
01234                 LCleanedupHandle<RFs> managedFs;
01235                 managedFs->Connect();
01236                 //default cleanup strategy is to call RFs::Close() on scope exit;
01237                 }
01238                 
01239                 {
01240                 LCleanedupHandle<RSimple, TFree> simple;
01241                 simple->OpenL(23);
01242                 //Specified cleanup strategy is to call RSimple::Free() on scope exit;
01243                 }
01244         
01245                 /*
01246                 Because the DEFINE_CLEANUP_FUNCTION is defined above, the default
01247                 cleanup function for RSimple is RSimple::ReleaseData() rather than
01248                 RSimple::Close()
01249                 */
01250                 {
01251                 LCleanedupHandle<RSimple> simple;
01252                 simple->OpenL(23);
01253                 //Custom cleanup strategy is to call RSimple::ReleaseData() on scope exit
01254                 }
01255                 
01256                 {
01257                 RSimple simple;
01258                 
01259                 //The RSimple class above defines a static cleanup function
01260                 //RSimple::Cleanup().
01261                 LCleanedupGuard guard(RSimple::Cleanup, &simple);
01262 
01263                 simple.OpenL(10);
01264                 
01265                 //On scope exit RSimple::Cleanup() is called passing &simple.
01266                 }
01267         }
01268 
01269 void WalkthroughUsageL()
01270         {
01271         _LIT(KTxtOption3,"Option3: Memory used by EUser high level classes\n");
01272         gConsole->Printf(KTxtOption3);
01273         RFile file;
01274         
01275         _LIT(KTxtSizeofRFile,"Size of RFile = %d\n");
01276         gConsole->Printf(KTxtSizeofRFile, sizeof(file));
01277         
01278         LCleanedupHandle<RFile> cFile;
01279         
01280         _LIT(KTxtSizeofLCleanedupHandleRFile,"Size of LCleanedupHandle<RFile> = %d\n");
01281         gConsole->Printf(KTxtSizeofLCleanedupHandleRFile, sizeof(cFile));
01282         gConsole->Printf(KTxtPressAnyKeyToContinue);
01283         gConsole->Getch();
01284         
01285         LCleanedupRef<RFile> crFile(file);      
01286         _LIT(KTxtSizeofLCleanedupRefRFile,"Size of LCleanedupRef<RFile> = %d\n");
01287         gConsole->Printf(KTxtSizeofLCleanedupRefRFile, sizeof(crFile));
01288         gConsole->Printf(KTxtPressAnyKeyToContinue);
01289         gConsole->Getch();
01290 
01291         CTicker* tracker = new(ELeave) CTicker;
01292         _LIT(KTxtSizeofCTracker,"Size of CTracker* = %d\n");
01293         gConsole->Printf(KTxtSizeofCTracker, sizeof(tracker));
01294         gConsole->Printf(KTxtPressAnyKeyToContinue);
01295         gConsole->Getch();
01296         
01297         LCleanedupPtr<CTicker> cTracker(tracker);
01298         _LIT(KTxtSizeofLCleanedupHandleCTicker,"Size of LCleanedupPtr<CTicker> = %d\n");
01299         gConsole->Printf(KTxtSizeofLCleanedupHandleCTicker, sizeof(LCleanedupPtr<CTicker>));
01300         gConsole->Printf(KTxtPressAnyKeyToContinue);
01301         gConsole->Getch();
01302         }
01303 
01304 TInt TestL()
01305         {
01306         gConsole=Console::NewL(KTxtExample,TSize(KConsFullScreen,KConsFullScreen));
01307         CleanupStack::PushL(gConsole);
01308         gConsole->Printf(KTxtExample);
01309         gConsole->Printf(KTxtPressAnyKeyToContinue);
01310         gConsole->Getch();      
01311         WalkthroughStringsL();
01312         gConsole->Printf(KTxtPressAnyKeyToContinue);
01313         gConsole->Getch();
01314         WalkthroughManagedL();
01315         gConsole->Printf(KTxtPressAnyKeyToContinue);
01316         gConsole->Getch();
01317         WalkthroughUsageL();
01318         _LIT(KTxtPressAnyKeyToExit,"\nPress any key to exit");
01319         gConsole->Printf(KTxtPressAnyKeyToExit);
01320         gConsole->Getch();
01321         CleanupStack::PopAndDestroy(gConsole); // delete the gConsole
01322         return KErrNone;
01323         }
01324 
01325 TInt E32Main()
01326         {       
01327         __UHEAP_MARK;
01328         CTrapCleanup* cleanup=CTrapCleanup::New(); // Create clean-up stack.
01329         TInt status;
01330         if(cleanup!=NULL)
01331                 {
01332             TRAP(status, TestL());
01333                 __ASSERT_ALWAYS(!status,User::Panic(KTxtExample,status));
01334                 }
01335         delete cleanup; // Delete clean-up stack.       
01336         __UHEAP_MARKEND;
01337         
01338         return status;
01339         }
01340 
01341 
01342 // eof

Generated by  doxygen 1.6.2