examples/SysLibs/EUserHLExample/src/euserhlexample.cpp

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

Generated by  doxygen 1.6.2