diff -r 89d6a7a84779 -r 25a17d01db0c Symbian3/Examples/guid-6013a680-57f9-415b-8851-c4fa63356636/euserhlexample_8cpp-source.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Symbian3/Examples/guid-6013a680-57f9-415b-8851-c4fa63356636/euserhlexample_8cpp-source.html Fri Jan 22 18:26:19 2010 +0000 @@ -0,0 +1,1308 @@ + +
+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 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 +