diff -r f345bda72bc4 -r 43e37759235e Symbian3/Examples/guid-6013a680-57f9-415b-8851-c4fa63356636/euserhlexample_8cpp-source.html --- a/Symbian3/Examples/guid-6013a680-57f9-415b-8851-c4fa63356636/euserhlexample_8cpp-source.html Tue Mar 30 11:56:28 2010 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1308 +0,0 @@ - -
-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 -