os/ossrv/lowlevellibsandfws/genericusabilitylib/example/src/euserhl_walkthrough.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include <e32std.h>
    17 #include <f32file.h>
    18 #include <e32test.h>
    19 #include <euserhl.h>
    20 
    21 
    22 
    23 // Note: Methods are defined inline within classes here simply to make
    24 // the code shorter, keep related code closer together, and hopefully
    25 // make things easier to follow.
    26 
    27 RTest test(_L("EuserHl Walkthrough"));
    28 
    29 // Some dummy methods and data used in the walkthroughs below
    30 _LIT(KFill, "XXX");
    31 _LIT(KPath, "c:\\a\\b\\c");
    32 _LIT(KOne, "One ");
    33 _LIT(KTwo, "Two ");
    34 _LIT(KTesting, "Testing ");
    35 
    36 void MaybeLeaveL()
    37 	{
    38 	// Some code that may leave
    39 	}
    40 
    41 HBufC* AllocateNameL(const TDesC& aDes)
    42 	{
    43 	return aDes.AllocL();
    44 	}
    45 
    46 void ReadToMax(TDes& aDes)
    47 	{
    48 	aDes.SetMax();
    49 	aDes.Repeat(KFill);
    50 	}
    51 
    52 void GetCurrentPath(TDes& aDes)
    53 	{
    54 	aDes = KPath;
    55 	}
    56 
    57 void GetCurrentPathStringL(LString& aString)
    58 	{
    59 	aString = L"c:\\a\\b\\c"; // Will auto-grow if necessary, may leave
    60 	}
    61 
    62 LString AppendCurrentPathStringL(LString aString)
    63 	{
    64 	return aString+= L"c:\\a\\b\\c";
    65 	}
    66 
    67 class CTicker : public CBase
    68 	{
    69 public:
    70 	void Tick() { ++iTicks; }
    71 	void Tock() { ++iTocks; }
    72 
    73 	void Zap() { delete this; }
    74 
    75 public:
    76 	TInt iTicks;
    77 	TInt iTocks;
    78 	};
    79 
    80 // Defines a custom pointer cleanup policy that calls the Zap member
    81 class TTickerZapStrategy
    82 	{
    83 public:
    84 	static void Cleanup(CTicker* aPtr)
    85 		{
    86 		// The general template/class scaffolding remains the same
    87 		// for all custom cleanups, just this cleanup body varies
    88 		aPtr->Zap();
    89 		test.Printf(_L("Zapped CTicker\n"));
    90 		}
    91 	};
    92 
    93 void RegisterTicker(CTicker& aTicker)
    94 	{
    95 	(void)aTicker;
    96 	}
    97 
    98 void RegisterTickerPtr(CTicker* aTicker)
    99 	{
   100 	(void)aTicker;
   101 	}
   102 
   103 void TakeTickerOwnership(CTicker* aTicker)
   104 	{
   105 	delete aTicker;
   106 	}
   107 
   108 void RegisterTimer(RTimer& aTimer)
   109 	{
   110 	(void)aTimer;
   111 	}
   112 
   113 // Defines a custom handle cleanup policy that calls Cancel then Close
   114 class TCancelClose
   115 	{
   116 public:
   117 	template <class T>
   118 	static void Cleanup(T* aHandle)
   119 		{
   120 		// The general template/class scaffolding remains the same
   121 		// for all custom cleanups, just this cleanup body varies
   122 		aHandle->Cancel();
   123 		aHandle->Close();
   124 		test.Printf(_L("Cancel Closed RTimer\n"));
   125 		}
   126 	};
   127 
   128 void BespokeCleanupFunction(TAny* aData)
   129 	{
   130 	(void)aData;
   131 	test.Printf(_L("BespokeCleanupFunction\n"));
   132 	}
   133 
   134 // The walkthroughs themselves
   135 
   136 // This class demonstrates the use of an embedded LString in the
   137 // conventional Symbian two-phase construction pattern. We've chosen
   138 // to implement the temporary leave protection in NewL in terms of
   139 // LCleanedupPtr instead of the the CleanupStack API in this example.
   140 class CStringUserTwoPhase : public CBase
   141 	{
   142 public:
   143 	static CStringUserTwoPhase* NewL(const TDesC& aName)
   144 		{
   145 		// We can use the resource management utility classes in
   146 		// two-phase if we want to
   147 		LCleanedupPtr<CStringUserTwoPhase> self(new(ELeave) CStringUserTwoPhase);
   148 		self->ConstructL(aName);
   149 		// Calling Unmanage() disables cleanup and yields the
   150 		// previously managed pointer so that it can be safely
   151 		// returned
   152 		return self.Unmanage(); 
   153 		}
   154 
   155 	virtual void ConstructL(const TDesC& aName)
   156 		{
   157 		// This assignment may leave if LString fails to allocate a
   158 		// heap buffer large enough to hold the data in aName
   159 		iName = aName; 
   160 		}
   161 
   162 	~CStringUserTwoPhase()
   163 		{
   164 		// The iName LString cleans up after itself automatically 
   165 		}
   166 
   167 	const TDesC& Name() 
   168 		{
   169 		// We can just return an LString directly as a const TDesC
   170 		return iName; 
   171 		}
   172 
   173 protected:
   174 	CStringUserTwoPhase()
   175 		{
   176 		// Everything interesting happens in ConstructL in this
   177 		// version. 
   178 
   179 		// Default initialization of the iName LString does not
   180 		// allocate a heap buffer, and so cannot leave. As long as
   181 		// initialization is deferred to ConstructL, LStrings can be
   182 		// used safely with two-phase construction.
   183 		}
   184 
   185 protected:
   186 	LString iName;
   187 	};
   188 
   189 // This class demonstrates the use of an embedded LString in the
   190 // single-phase construction pattern, where a leave-safe constructor
   191 // fully initializes the object. 
   192 //
   193 // Note that where a class's constructor forms part of its exported
   194 // public or protected contract, switching from a non-leaving to a
   195 // potentially leaving constructor would be a BC break. On the other
   196 // hand, if instantiation is entirely encapsulated within factory
   197 // functions like NewL, there is no such BC restriction.
   198 class CStringUserSinglePhase : public CBase
   199 	{
   200 public:
   201 	// This macro is necessary to ensure cleanup is correctly handled
   202 	// in the event that a constructor may leave beneath a call to
   203 	// new(ELeave)
   204 	CONSTRUCTORS_MAY_LEAVE
   205 
   206 	static CStringUserSinglePhase* NewL(const TDesC& aName)
   207 		{
   208 		return new(ELeave) CStringUserSinglePhase(aName);
   209 		}
   210 
   211 	~CStringUserSinglePhase()
   212 		{
   213 		// The iName LString cleans up after itself automatically
   214 		}
   215 
   216 	const TDesC& Name() 
   217 		{
   218 		// We can just return an LString directly as a const TDesC
   219 		return iName;
   220 		}
   221 
   222 protected:
   223 	CStringUserSinglePhase(const TDesC& aName)
   224 		// This initialization of iName may leave because LString
   225 		// needs to allocate a heap buffer to copy the aName string
   226 		// data into
   227 		: iName(aName) 
   228 		{
   229 		// If iName initialization is successful but the constructor
   230 		// then goes on to leave later, iName (like all fields fully
   231 		// constructed at the point of a leave in a constructor) will
   232 		// be destructed, and so clean up after itself
   233 		MaybeLeaveL();
   234 		}
   235 
   236 protected:
   237 	LString iName;
   238 	};
   239 
   240 
   241 void WalkthroughStringsL()
   242 	{
   243 
   244 		{
   245 		// Trivially exercise the LString using classes defined above
   246 
   247 		LCleanedupPtr<CStringUserTwoPhase> one(CStringUserTwoPhase::NewL(KOne));
   248 		test.Printf(_L("Single phase name: %S\n"), &one->Name());
   249 
   250 		LCleanedupPtr<CStringUserSinglePhase> two(CStringUserSinglePhase::NewL(KTwo));
   251 		test.Printf(_L("Two phase name: %S\n"), &two->Name());
   252 
   253 		// Both instances are automatically deleted as we go out of scope
   254 		}
   255 
   256 		{
   257 		// A default constructed LString starts empty, doesn't
   258 		// allocate any memory on the heap, and therefore the
   259 		// following cannot leave
   260 		LString s;
   261 
   262 		// But it will grow on demand if you assign to it, so it has
   263 		// enough space to hold the copied string data, and so
   264 		// assignment may leave
   265 		s = L"One ";
   266 
   267 		// Similarly if you append to it with the leaving variant of
   268 		// Append, AppendL, if may grow on demand
   269 		s.AppendL(L"Two ");
   270 
   271 		// The += operator for LString also maps to AppendL
   272 		s += L"Three ";
   273 
   274 		// You can also use new leaving format methods that also grow
   275 		// on demand
   276 		s.AppendFormatL(KTesting);
   277 
   278 		// This general style of use of LString may be preferable to
   279 		// typical descriptor use for a number of reasons e.g. it
   280 		// avoids the common temptation to set an artificial maximum
   281 		// buffer size; it avoids massive conservative over-allocation
   282 		// when the average case length of a string is far less than
   283 		// the worst-case maximum; it will not surprise you (compared
   284 		// to the alternative of a large stack-allocated TBuf) by
   285 		// triggering stack overflow.
   286 
   287 		// An LString can be printed the same way as any descriptor
   288 		test.Printf(_L("Value: %S\n"), &s);
   289 
   290 		// An LString supports all TDesC and TDes methods
   291 		// LString findToken(L"Two ");
   292 		test(s.Find(L"Two ") == 4);
   293 		
   294 		// LString matchPattern(L"*Two* ");
   295 		test(s.Match(L"*Two*") == 4);
   296 		test(s.Match(L"*T?o*") == 4);
   297 		
   298 		// LString compare(L"some string");
   299 		test(s.Compare(L"One Two Three Testing ") == 0);
   300 		test(s.Compare(L"One Two Three Testing! ") < 0);
   301 		test(s.Compare(L"One Two Testing ") > 0);
   302 		
   303 		// also LString ==,!=,>,<,<=,>=(L"some string");
   304 		test(s == L"One Two Three Testing ");
   305 		test(s < L"One Two Three Testing! ");
   306 		test(s > L"One Two Testing ");
   307 		test(s != L"not equal");
   308 		
   309 		// An LString supports all TDesC and TDes operators
   310 		test(s[4] == TChar('T'));
   311 
   312 		TInt untrimmed = s.Length();
   313 		s.Trim();
   314 		test(s.Length() == untrimmed - 1);
   315 
   316 		s.UpperCase();
   317 		test.Printf(_L("UpperCase: %S\n"), &s);
   318 		s.LowerCase();
   319 		test.Printf(_L("LowerCase: %S\n"), &s);
   320 
   321 		// The underlying heap allocated buffer is released
   322 		// automatically when the LString goes out of scope, either
   323 		// normally or through a leave
   324 		}
   325 		{
   326 		// Copy, Append,Insert,Replace,Justify the same way as TDesC and TDes
   327 		
   328 		LString s;
   329 		// Copies data into this 8-bit string descriptor, replacing any existing
   330 		// data, and expanding its heap buffer to accommodate if necessary.
   331 		// leaves on not being able to accomodate the new content
   332 		// both AssignL and += use CopyL internally
   333 		s.CopyL(L"new way of dealing with strings");
   334 		s.CopyUCL(L"new way of dealing with strings");
   335 		test(s == L"NEW WAY OF DEALING WITH STRINGS");
   336 		
   337 		// Insert data into this descriptor.
   338 		// The length of this descriptor is changed to reflect the extra data.
   339 		// This leaving variant of the standard, non-leaving descriptor method
   340 		// differs in that this operation may cause the string descriptor's heap
   341 		// buffer to be reallocated in order to accommodate the new data. As a
   342 		// result, MaxLength() and Ptr() may return different values afterwards,
   343 		// and any existing raw pointers to into the descriptor data may be
   344 		// invalidated.
   345 		s.CopyL(L"Some Content Can Be Into This String");
   346 		s.InsertL(20,L"Inserted ");
   347 		test(s == L"Some Content Can Be Inserted Into This String");
   348 		
   349 		// Replace data in this descriptor.
   350 		// The specified length can be different to the length of the replacement data.
   351 		// The length of this descriptor changes to reflect the change of data.
   352 		// This leaving variant of the standard, non-leaving descriptor method
   353 		// differs in that this operation may cause the string descriptor's heap
   354 		// buffer to be reallocated in order to accommodate the new data. As a
   355 		// result, MaxLength() and Ptr() may return different values afterwards,
   356 		// and any existing raw pointers to into the descriptor data may be
   357 		// invalidated.
   358 		s.CopyL(L"Some Content Can Be Decalper");
   359 		s.ReplaceL(20,8,L"Replaced");
   360 		test(s == L"Some Content Can Be Replaced");
   361 		
   362 		// Append data onto the end of this descriptor's data.
   363 		// The length of this descriptor is incremented to reflect the new content.
   364 		// This leaving variant of the standard, non-leaving descriptor method
   365 		// differs in that this operation may cause the string descriptor's heap
   366 		// buffer to be reallocated in order to accommodate the new data. As a
   367 		// result, MaxLength() and Ptr() may return different values afterwards,
   368 		// and any existing raw pointers to into the descriptor data may be
   369 		// invalidated.
   370 		s.CopyL(L"Try appending ");
   371 		s.AppendL(L"Try appending some more",3);
   372 		test(s == L"Try appending Try");
   373 		
   374 		// Copy data into this descriptor and justifies it, replacing any existing data.
   375 		// The length of this descriptor is set to reflect the new data.
   376 		// The target area is considered to be an area of specified width positioned at
   377 		// the beginning of this descriptor's data area. Source data is copied into, and
   378 		// aligned within this target area according to the specified alignment
   379 		// instruction.
   380 		// If the length of the target area is larger than the length of the source, then
   381 		// spare space within the target area is padded with the fill character.
   382 		// This leaving variant of the standard, non-leaving descriptor method
   383 		// differs in that this operation may cause the string descriptor's heap
   384 		// buffer to be reallocated in order to accommodate the new data. As a
   385 		// result, MaxLength() and Ptr() may return different values afterwards,
   386 		// and any existing raw pointers to into the descriptor data may be
   387 		// invalidated.
   388 		s.CopyL(L"Justified");
   389 		s.JustifyL(L"Just",9,ERight,'x');
   390 		test(s == L"xxxxxJust");
   391 		
   392 		// Append data onto the end of this descriptor's data and justifies it.
   393 		// The source of the appended data is a memory location.
   394 		// The target area is considered to be an area of specified width, immediately 
   395 		// following this descriptor's existing data. Source data is copied into, and 
   396 		// aligned within, this target area according to the specified alignment instruction.
   397 		// If the length of the target area is larger than the length of the source, 
   398 		// then spare space within the target area is padded with the fill character.
   399 		// This leaving variant of the standard, non-leaving descriptor method
   400 		// differs in that this operation may cause the string descriptor's heap
   401 		// buffer to be reallocated in order to accommodate the new data. As a
   402 		// result, MaxLength() and Ptr() may return different values afterwards,
   403 		// and any existing raw pointers to into the descriptor data may be
   404 		// invalidated.
   405 		s.CopyL(L"One ");
   406 		s.AppendJustifyL(L"Two Three",3,7,ERight,'x');
   407 		test(s == L"One xxxxTwo" );
   408 		
   409 		}
   410 		{
   411 		// You can initialize with a MaxLength value
   412 		LString s(KMaxFileName); // This operation may leave
   413 		test(s.MaxLength() == KMaxFileName);
   414 
   415 		// And you can dynamically adjust MaxLength later using 
   416 		// SetMaxLengthL if you want an exact allocated size
   417 		// Setting MaxLength on construction or via SetMaxLengthL is
   418 		// exact; calling MaxLength() immediately afterwards is
   419 		// guaranteed to return exactly the value you specified
   420 		s.SetMaxLengthL(2 * KMaxFileName);
   421 		test(s.MaxLength() == 2 * KMaxFileName);
   422 
   423 		// Pre-setting MaxLength is important when passing an LString
   424 		// as a TDes to a library function, because the LString can't
   425 		// be auto-grown via the TDes API
   426 
   427 		}
   428 
   429 		{
   430 		// You can initialize from any descriptor/literal/[wide]character string and the
   431 		// string data is copied into the LString
   432 		LString s(L"One "); // From a character string
   433 		s += L"Two ";
   434 		LString half(s.Left(s.Length() / 2)); // Left returns a TPtrC
   435 		test.Printf(_L("All: %S, Half: %S\n"), &s, &half);
   436 
   437 		// On the other hand, you can initialize from a returned
   438 		// HBufC* and the LString automatically takes ownership
   439 		LString own(AllocateNameL(KTesting));
   440 		test.Printf(_L("What I own: %S\n"), &own);
   441 
   442 		// Following that you can re-assign an HBufC to an existing
   443 		// string using the assignment operator 
   444 		// taking ownership of the new content. 
   445 		own = AllocateNameL(KTesting);
   446 		
   447 		// Following that you can re-assign an HBufC to an existing
   448 		// string. The string destroys its original content before
   449 		// taking ownership of the new content. 
   450 		own.Assign(AllocateNameL(KTesting));
   451 		
   452 		// The content of one string can similarly be assigned
   453 		// to another to avoid copying. In this example, the content 
   454 		// is detached from 's' and transfered to 'own'.  
   455 		own.Assign(s);
   456 		
   457 		// The same content transfer can be achieved from an RBuf to a
   458 		// string. You may need to do this if a legacy method returns
   459 		// you an RBuf. The RBuf is emptied of its content.
   460 		RBuf16 buf;
   461 		buf.CreateL(KOne);
   462 		own.Assign(buf);
   463 	
   464 		// You can also assign a simple text array to a string as its
   465 		// new buffer. This method initialises the length to zero.   
   466 		own.Assign((TText*)User::Alloc(24*(TInt)sizeof(TText)), 24);
   467 		
   468 		// If the buffer has already been filled with some characters
   469 		// then you supply the length in this alternative Assign method.   
   470 		own.Assign((TText*)User::Alloc(24*(TInt)sizeof(TText)), 12,24);
   471 
   472 		// Each Assign destroys the old content before assuming ownership
   473 		// of the new.
   474 		// As usual the last content of the string is destroyed when the 
   475 		// LString goes out of scope
   476 		}
   477 
   478 		{
   479 		// You can reserve extra free space in preparation for an 
   480 		// operation that adds characters to the string. You may
   481 		// need to do this when you cannot use any of the auto-buffer
   482 		// extending LString methods to achieve your objective.
   483 		LString s(L"One ");
   484 		s.ReserveFreeCapacityL(4);
   485 		test(s.Length() == 4);
   486 		test(s.MaxLength() >= 8);
   487 
   488 		// Almost all the methods that may extended the string buffer,
   489 		// including the explicit ReserveFreeCapacityL, but excluding
   490 		// SetMaxLengthL, attempt to grow the size exponentially. 
   491 		// The Exponential growth pattern is expected to give better 
   492 		// performance at an amortised complexity of O(n) when adding n characters.
   493 		// If the exponential growth is less than the supplied extra size
   494 		// then the supplied size is used instead to save time.
   495 		// The exponential growth is used in anticipation of further additions
   496 		// to a string. This trades-off speed efficiency for space efficiency.
   497 		// If required you may be able to swap the oversized buffer for 
   498 		// a more compact one using:
   499 		s.Compress();
   500 		test(s.MaxLength() >= 4);	//note indefinite test
   501 		    
   502 		// Resize attempts to re-allocate a smaller buffer to copy
   503 		// the content into. If the new memory cannot be allocated then the
   504 		// original string is left unaffected. 
   505 		
   506 		// When you have finished using the content of a string you can
   507 		// get its buffer released without destroying the string itself. 
   508 		// You may want to do this when using member declared strings.
   509 		// Automatic strings are destroyed when they go out of scope.
   510 		s.Reset();
   511 		test(s.Length() == 0);
   512 		test(s.MaxLength() == 0);
   513 		
   514 		}
   515 
   516 		{
   517 		// An LString can be passed directly to any function requiring
   518 		// a const TDesC&
   519 		TInt year = 2009;
   520 
   521 		LString s;
   522 		s.FormatL(_L("Happy New Year %d"), year);
   523 		// InfoPrint takes a const TDesC&
   524 		User::InfoPrint(s);
   525 
   526 		LString pattern;
   527 		pattern.FormatL(_L("*Year %d"), year);
   528 		// Match takes a const TDesC& as a pattern
   529 		TInt loc = s.Match(pattern);
   530 		test(loc == 10);
   531 		}
   532 
   533 		{
   534 		// An LString can be passed directly to any function requiring
   535 		// a TDes& but care must always be taken to pre-set MaxLength
   536 		// since LStrings can't be automatically grown via the TDes
   537 		// interface
   538 
   539 		LString s;
   540 		// Calling GetCurrentPath(s) now would panic because LStrings
   541 		// are initialized by default to MaxLength 0.  Although s is
   542 		// an LString GetCurrentPath takes a TDes& and so inside the function
   543 		// s behaves as a TDes and would panic with USER 11 if the resulting 
   544 		// new length of s is greater than its maximum length.
   545 		test(s.MaxLength() == 0);
   546 
   547 		// Calling SetMaxLengthL will automatically realloc the
   548 		// underlying buffer if required, and is guaranteed to leave
   549 		// MaxLength() equal to the specified value
   550 		s.SetMaxLengthL(KMaxFileName);
   551 		GetCurrentPath(s);
   552 		//LString pathString(L"c:\\a\\b\\c");
   553 		test.Printf(_L("Path: %S\n"), &s);
   554 		test(s == L"c:\\a\\b\\c");
   555 
   556 		// If SetMaxLengthL adjusts MaxLength lower than the current
   557 		// Length, the data is truncated to the new MaxLength and
   558 		// Length set to the new MaxLength
   559 		s.SetMaxLengthL(s.Length() / 2);
   560 		test.Printf(_L("Truncated path: %S\n"), &s);
   561 		test(s.Length() == s.MaxLength());
   562 
   563 		// An initial MaxLength can be specified when constructing an
   564 		// LString. Note that unlike the default constructor, this
   565 		// variant allocates and may leave.
   566 		LString s2(KMaxFileName);
   567 		GetCurrentPath(s2);
   568 		test.Printf(_L("Path: %S\n"), &s2);
   569 		test(s2 == L"c:\\a\\b\\c");
   570 
   571 		// Your code and APIs can benefit from LString's auto-growth
   572 		// behaviour by accepting an LString to fill in as an output
   573 		// parameter. Using LString rather than TDes parameters means 
   574 		// that the function is able to safely increase the size of the 
   575 		// string as the LString will re-allocate as necessary
   576 		LString s3;
   577 		// GetCurrentPathStringL takes an LString&
   578 		GetCurrentPathStringL(s3);
   579 		test.Printf(_L("Path: %S\n"), &s3);
   580 		test(s3 == L"c:\\a\\b\\c");
   581 
   582 		// As a well-defined value class, if you want to, LStrings can
   583 		// be passed and returned by value. This is relatively
   584 		// inefficient however due to the amount of copying and heap
   585 		// reallocation involved. 
   586 		LString s4(AppendCurrentPathStringL(s3));
   587 		test.Printf(_L("Appended path: %S\n"), &s4);
   588 		test(s4.Length() == s3.Length() * 2);
   589 		}
   590 
   591 		{
   592 		// LStrings can be allocated on the heap if necessary. 
   593 		// Then it can managed as part of an array of string pointers
   594 		TInt n = 5;
   595 		LCleanedupHandle<RPointerArray<LString>, TResetAndDestroy> sarray;
   596 
   597 		for (TInt i = 0; i < n; ++i) 
   598 			{
   599 			LString* s = new(ELeave) LString;
   600 			s->FormatL(_L("String %d"), i);
   601 			sarray->Append(s);
   602 			}
   603 
   604 		for (TInt i = 0, n = sarray->Count(); i < n; ++i) 
   605 			{
   606 			LString tmp;
   607 			tmp.FormatL(_L("String %d"), i);
   608 			test(tmp == *(*sarray)[i]);
   609 			test.Printf(_L("String %d = %S\n"), i, (*sarray)[i]);
   610 			}
   611 
   612 		}
   613 
   614 		{
   615 		// Any allocation failure in new(ELeave)LString throws
   616 		// KErrNoMemory and cleans up after itself fully
   617 
   618 		__UHEAP_MARK;
   619 		//coverity[resource_leak]
   620 		//As mentioned in the comment above any allocation failure is taken care of
   621 		TRAPD(status, new(ELeave) LString(100 * 1024 * 1024));
   622 		test(status == KErrNoMemory);
   623 		__UHEAP_MARKEND;
   624 		}
   625 
   626 		{
   627 		// Native C arrays (both heap and stack allocated) of LStrings
   628 		// also work, although their use is not recommended
   629 
   630 		TInt n = 5;
   631 		LCleanedupArray<LString> sarray(new(ELeave) LString[n]);
   632 
   633 		for (TInt i = 0; i < n; ++i) 
   634 			{
   635 			sarray[i].FormatL(_L("String %d"), i);
   636 			}
   637 
   638 		for (TInt i = 0; i < n; ++i) 
   639 			{
   640 			LString tmp;
   641 			tmp.FormatL(_L("String %d"), i);
   642 			test(tmp == sarray[i]);
   643 			test.Printf(_L("String %d = %S\n"), i, &sarray[i]);
   644 			}
   645 
   646 		}
   647 		{
   648 		// 8-bit wide null terminated character string support
   649 		
   650 		// A default constructed LString8 starts empty, doesn't
   651 		// allocate any memory on the heap, and therefore the
   652 		// following cannot leave
   653 		LString8 s;
   654 
   655 		// But it will grow on demand if you assign to it, so it has
   656 		// enough space to hold the copied string data, and so
   657 		// assignment may leave
   658 		s ="One ";
   659 
   660 		// Similarly if you append to it with the leaving variant of
   661 		// Append, AppendL, if may grow on demand
   662 		s.AppendL("Two ");
   663 
   664 		// The += operator for LString8 also maps to AppendL
   665 		s +="Three ";
   666 		s +="Testing ";
   667 
   668 		// An LString8 can be printed the same way as any descriptor
   669 		test.Printf(_L("Value: %S \n"), &s);
   670 
   671 		// An LString8 can be compared the same way as any descriptor
   672 		test(s == "One Two Three Testing ");
   673 
   674 		// An LString8 supports all TDesC and TDes methods
   675 		// LString findToken("Two ");
   676 		test(s.Find("Two ") == 4);
   677 		
   678 		// LString8 matchPattern("*Two* ");
   679 		test(s.Match("*Two*") == 4);
   680 		test(s.Match("*T?o*") == 4);
   681 		
   682 		// LString8 compare("some string");
   683 		test(s.Compare("One Two Three Testing ") == 0);
   684 		test(s.Compare("One Two Three Testing! ") < 0);
   685 		test(s.Compare("One Two Testing ") > 0);
   686 		
   687 		// also LString8 ==,!=,>,<,<=,>=(L"some string");
   688 		test(s == "One Two Three Testing ");
   689 		test(s < "One Two Three Testing! ");
   690 		test(s > "One Two Testing ");
   691 		test(s != "not equal");
   692 		
   693 		// Copies data into this 8-bit string descriptor, replacing any existing
   694 		// data, and expanding its heap buffer to accommodate if necessary.
   695 		// leaves on not being able to accomodate the new content
   696 		// both AssignL and += use CopyL internally
   697 		s.CopyL("new way of dealing with strings");
   698 		
   699 
   700 		// Copy, Append,Insert,Replace,Justify the same way as TDesC8 and TDes8
   701 
   702 		// Copies data into this 8-bit string descriptor, replacing any existing
   703 		// data, and expanding its heap buffer to accommodate if necessary.
   704 		// leaves on not being able to accomodate the new content
   705 		// both AssignL and += use CopyL internally
   706 		s.CopyL("new way of dealing with strings");
   707 		s.CopyUCL("new way of dealing with strings");
   708 		test(s == "NEW WAY OF DEALING WITH STRINGS");
   709 		
   710 		// Insert data into this descriptor.
   711 		// The length of this descriptor is changed to reflect the extra data.
   712 		// This leaving variant of the standard, non-leaving descriptor method
   713 		// differs in that this operation may cause the string descriptor's heap
   714 		// buffer to be reallocated in order to accommodate the new data. As a
   715 		// result, MaxLength() and Ptr() may return different values afterwards,
   716 		// and any existing raw pointers to into the descriptor data may be
   717 		// invalidated.
   718 		s.CopyL("Some Content Can Be Into This String");
   719 		s.InsertL(20,"Inserted ");
   720 		test(s == "Some Content Can Be Inserted Into This String");
   721 		
   722 		// Replace data in this descriptor.
   723 		// The specified length can be different to the length of the replacement data.
   724 		// The length of this descriptor changes to reflect the change of data.
   725 		// This leaving variant of the standard, non-leaving descriptor method
   726 		// differs in that this operation may cause the string descriptor's heap
   727 		// buffer to be reallocated in order to accommodate the new data. As a
   728 		// result, MaxLength() and Ptr() may return different values afterwards,
   729 		// and any existing raw pointers to into the descriptor data may be
   730 		// invalidated.
   731 		s.CopyL("Some Content Can Be Decalper");
   732 		s.ReplaceL(20,8,"Replaced");
   733 		test(s == "Some Content Can Be Replaced");
   734 		
   735 		// Append data onto the end of this descriptor's data.
   736 		// The length of this descriptor is incremented to reflect the new content.
   737 		// This leaving variant of the standard, non-leaving descriptor method
   738 		// differs in that this operation may cause the string descriptor's heap
   739 		// buffer to be reallocated in order to accommodate the new data. As a
   740 		// result, MaxLength() and Ptr() may return different values afterwards,
   741 		// and any existing raw pointers to into the descriptor data may be
   742 		// invalidated.
   743 		s.CopyL("Try appending ");
   744 		s.AppendL("Try appending some more",3);
   745 		test(s == "Try appending Try");
   746 		
   747 		// Copy data into this descriptor and justifies it, replacing any existing data.
   748 		// The length of this descriptor is set to reflect the new data.
   749 		// The target area is considered to be an area of specified width positioned at
   750 		// the beginning of this descriptor's data area. Source data is copied into, and
   751 		// aligned within this target area according to the specified alignment
   752 		// instruction.
   753 		// If the length of the target area is larger than the length of the source, then
   754 		// spare space within the target area is padded with the fill character.
   755 		// This leaving variant of the standard, non-leaving descriptor method
   756 		// differs in that this operation may cause the string descriptor's heap
   757 		// buffer to be reallocated in order to accommodate the new data. As a
   758 		// result, MaxLength() and Ptr() may return different values afterwards,
   759 		// and any existing raw pointers to into the descriptor data may be
   760 		// invalidated.
   761 		s.CopyL("Justified");
   762 		s.JustifyL("Just",9,ERight,'x');
   763 		test(s == "xxxxxJust");
   764 		
   765 		// Append data onto the end of this descriptor's data and justifies it.
   766 		// The source of the appended data is a memory location.
   767 		// The target area is considered to be an area of specified width, immediately 
   768 		// following this descriptor's existing data. Source data is copied into, and 
   769 		// aligned within, this target area according to the specified alignment instruction.
   770 		// If the length of the target area is larger than the length of the source, 
   771 		// then spare space within the target area is padded with the fill character.
   772 		// This leaving variant of the standard, non-leaving descriptor method
   773 		// differs in that this operation may cause the string descriptor's heap
   774 		// buffer to be reallocated in order to accommodate the new data. As a
   775 		// result, MaxLength() and Ptr() may return different values afterwards,
   776 		// and any existing raw pointers to into the descriptor data may be
   777 		// invalidated.
   778 		s.CopyL("One ");
   779 		s.AppendJustifyL("Two Three",3,7,ERight,'x');
   780 		test(s == "One xxxxTwo" );
   781 		
   782 		}
   783 		
   784 	}
   785 
   786 // This class demonstrates the use of the embeddable management
   787 // classes in a conventional Symbian two-phase construction
   788 // pattern. 
   789 class CManagedUserTwoPhase : public CBase
   790 	{
   791 public:
   792 	static CManagedUserTwoPhase* NewL(CTicker* aTicker)
   793 		{
   794 		// We can use the resource management utility classes in
   795 		// two-phase if we want to
   796 		LCleanedupPtr<CManagedUserTwoPhase> self(new(ELeave) CManagedUserTwoPhase);
   797 		self->ConstructL(aTicker);
   798 		// Calling Unmanage() disables cleanup and yields the
   799 		// previously managed pointer so that it can be safely
   800 		// returned
   801 		return self.Unmanage(); 
   802 		}
   803 
   804 	~CManagedUserTwoPhase()
   805 		{
   806 		// The iTicker manager will automatically delete the CTicker
   807 		// The iTimer manager will automatically Close() the RTimer
   808 		}
   809 
   810 	CTicker& Ticker()
   811 		{
   812 		// If we dereference the management object we get a CTicker&
   813 		return *iTicker;
   814 		}
   815 
   816 	RTimer& Timer()
   817 		{
   818 		// If we dereference the management object we get an RTimer&
   819 		return *iTimer;
   820 		}
   821 
   822 private:
   823 	
   824 	virtual void ConstructL(CTicker* aTicker)
   825 		{
   826 		// Take ownership and manage aTicker 
   827 		iTicker = aTicker; 
   828 
   829 		// Note use of -> to indirect through the management wrapper
   830 		iTimer->CreateLocal() OR_LEAVE; 
   831 		}
   832 	
   833 	CManagedUserTwoPhase()
   834 		{
   835 		// Everything interesting happens in ConstructL in this
   836 		// version. 
   837 
   838 		// Default initialization of the iName LString does not
   839 		// allocate a heap buffer, and so cannot leave. As long as
   840 		// initialization is deferred to ConstructL, LStrings can be
   841 		// used safely with two-phase construction.
   842 		}
   843 
   844 private:
   845 	// We have to use LManagedXxx for fields, not LCleanedupXxx
   846 	LManagedPtr<CTicker> iTicker;
   847 	LManagedHandle<RTimer> iTimer;
   848 	};
   849 
   850 // This class demonstrates the use of embedded management classes in
   851 // the single-phase construction pattern, where a leave-safe
   852 // constructor fully initializes the object.
   853 //
   854 // Note that where a class's constructor forms part of its exported
   855 // public or protected contract, switching from a non-leaving to a
   856 // potentially leaving constructor would be a BC break. On the other
   857 // hand, if instantiation is entirely encapsulated within factory
   858 // functions like NewL, there is no such BC restriction.
   859 
   860 class CManagedUserSinglePhase : public CBase
   861 	{
   862 public:
   863 	// This macro is necessary to ensure cleanup is correctly handled
   864 	// in the event that a constructor may leave beneath a call to
   865 	// new(ELeave)
   866 	CONSTRUCTORS_MAY_LEAVE
   867 
   868 	static CManagedUserSinglePhase* NewL(CTicker* aTicker)
   869 		{
   870 		return new(ELeave) CManagedUserSinglePhase(aTicker);
   871 		}
   872 
   873 	~CManagedUserSinglePhase()
   874 		{
   875 		// The iTicker manager destructor will automatically Zap() the CTicker
   876 		// The iTimer manager destructor will automatically Close() the RTimer
   877 		}
   878 
   879 	CTicker& Ticker()
   880 		{
   881 		// If we dereference the management object we get a CTicker&
   882 		return *iTicker;
   883 		}
   884 
   885 	RTimer& Timer()
   886 		{
   887 		// If we dereference the management object we get an RTimer&
   888 		return *iTimer;
   889 		}
   890 
   891 private:
   892 	CManagedUserSinglePhase(CTicker* aTicker)
   893 		// Take ownership and manage aTicker. Note that initialization
   894 		// of the LManagedXxx classes does not actually leave, but
   895 		// initialization of the LCleanedupXxx classes can.
   896 		: iTicker(aTicker)
   897 		{
   898 		// If iTicker initialization is successful but the constructor
   899 		// then goes on to leave later, iTicker (like all fields fully
   900 		// constructed at the point of a leave in a constructor) will
   901 		// be destructed, and the manager will cleanup the CTicker
   902 
   903 		// Note use of -> to indirect through the management wrapper
   904 		iTimer->CreateLocal() OR_LEAVE; 
   905 
   906 		// Likewise if we leave here, both iTicker and iTimer will
   907 		// undergo managed cleanup
   908 		MaybeLeaveL();
   909 		}
   910 
   911 private:
   912 	// We have to use LManagedXxx for fields, not LCleanedupXxx
   913 	LManagedPtr<CTicker, TTickerZapStrategy> iTicker;
   914 	LManagedHandle<RTimer> iTimer;
   915 	};
   916 
   917 //Class definition of trivial R-Class
   918 class RSimple
   919 	{
   920 public:
   921 	
   922 	RSimple(){iData = NULL;}
   923 	
   924 	//Open function sets value
   925 	void OpenL(TInt aValue)
   926 		{
   927 		iData = new(ELeave) TInt(aValue);
   928 		}
   929 	
   930 	//Cleanup function – frees resource
   931 	void Close()
   932 		{
   933 		delete iData;
   934 		iData = NULL;
   935 		}
   936 
   937 	//Cleanup function – frees resource
   938 	void Free()
   939 		{
   940 		delete iData;
   941 		iData = NULL;
   942 		}
   943 
   944 	//Cleanup function – frees resource
   945 	void ReleaseData()
   946 		{
   947 		delete iData;
   948 		iData = NULL;
   949 		}
   950 	
   951 	//static cleanup function – frees aRSimple resources
   952 	static void Cleanup(TAny* aRSimple)
   953 		{
   954 		static_cast<RSimple*>(aRSimple)->Close();
   955 		}
   956 
   957 
   958 private:
   959 	TInt* iData;
   960 
   961 	};
   962 
   963 
   964 //This sets the default cleanup behaviour for the RSimple class to 
   965 //be RSimple::ReleaseData.
   966 //If this Macro is not used then the default cleanup behaviour
   967 //would be to call RSimple::Close().
   968 DEFINE_CLEANUP_FUNCTION(RSimple, ReleaseData);
   969 
   970 
   971 void WalkthroughManagedL()
   972 	{
   973 		{
   974 		// Trivially exercise the manager-using classes defined above
   975 		CTicker* ticker1 = new(ELeave) CTicker;
   976 		LCleanedupPtr<CManagedUserTwoPhase> one(CManagedUserTwoPhase::NewL(ticker1));
   977 		test(&one->Ticker() == ticker1);
   978 		one->Timer().Cancel(); // Just to check we can get at it
   979 
   980 		CTicker* ticker2 = new(ELeave) CTicker;
   981 		LCleanedupPtr<CManagedUserSinglePhase> two(CManagedUserSinglePhase::NewL(ticker2));
   982 		test(&two->Ticker() == ticker2);
   983 		two->Timer().Cancel(); // Just to check we can get at it
   984 
   985 		// Both instances are automatically deleted as we go out of scope
   986 		}
   987 
   988 		// Always use LCleanedupXxx for locals, not LManagedXxx
   989 
   990 		{
   991 		// Begin the scenes the LCleanedupXxx constructors push a
   992 		// cleanup item onto the cleanup stack and so may leave. If
   993 		// there is a leave during construction, the supplied pointer
   994 		// will still get cleaned up.
   995 		LCleanedupPtr<CTicker> t(new(ELeave) CTicker);
   996 
   997 		// We can access CTicker's members via the management object
   998 		// using ->
   999 		t->Tick();
  1000 		t->Tock();
  1001 		test(t->iTicks == t->iTocks);
  1002 
  1003 		// We can get at a reference to the managed object using *
  1004 		// when we need to, e.g. if we need to pass it to a function
  1005 		RegisterTicker(*t); // Takes a CTicker&
  1006 
  1007 		// If some unfriendly interface needs a pointer rather than a
  1008 		// ref, we have a couple of options
  1009 		RegisterTickerPtr(&*t); // Takes a CTicker*
  1010 		RegisterTickerPtr(t.Get()); // Takes a CTicker*
  1011 
  1012 		// Note the use of . in t.Get() above; this distinguishes
  1013 		// operations on the managing type from operations on the
  1014 		// managed object
  1015 		
  1016 		// When the management object goes out of scope, either
  1017 		// normally or as the result of a leave, the managed object is
  1018 		// automatically deleted
  1019 		}
  1020 
  1021 		{
  1022 		// Sometimes you need to protect something temporarily before
  1023 		// transferring ownership e.g. by returning the pointer or
  1024 		// passing it to a function that takes ownership.
  1025 
  1026 		LCleanedupPtr<CTicker> t(new(ELeave) CTicker);
  1027 
  1028 		// Protected while we do this
  1029 		MaybeLeaveL(); 
  1030 
  1031 		// But now we want to hand it off, so we use Unmanage() to
  1032 		// both return a pointer and break the management link
  1033 		TakeTickerOwnership(t.Unmanage());
  1034 		
  1035 		// Now when it goes out of scope, no cleanup action is
  1036 		// performed
  1037 		}
  1038 
  1039 		{
  1040 		// If needed, it is possible to reuse a manager by using = to
  1041 		// assign it a new managed object.
  1042 
  1043 		// Not managing anything to start with
  1044 		LCleanedupPtr<CTicker> t;
  1045 		test(t.Get() == NULL);
  1046 		test(&*t == NULL);
  1047 
  1048 		for (TInt i = 0; i < 10; ++i)
  1049 			{
  1050 			// If an object is already being managed, it is cleaned up
  1051 			// before taking ownership of the new object
  1052 			t = new(ELeave) CTicker;
  1053 			}
  1054 		// We're left owning the final ticker instance, all prior
  1055 		// instances having been automatically deleted
  1056 		}
  1057 
  1058 		{
  1059 		// If you have stateful code where a pointer can sometimes be
  1060 		// NULL, as a convenience you can test the managing object
  1061 		// itself as a shortcut test for NULL
  1062 		LCleanedupPtr<CTicker> t(new(ELeave) CTicker);
  1063 
  1064 		// Does t refer to NULL?
  1065 		if (!t)
  1066 			{
  1067 			test(EFalse);
  1068 			}
  1069 
  1070 		t = NULL; // Also releases the currently managed CTicker 
  1071 
  1072 		// Does t refer to a non-NULL pointer?
  1073 		if (t)
  1074 			{
  1075 			test(EFalse);
  1076 			}
  1077 		}
  1078 
  1079 		{
  1080 		// LCleanedupPtr uses delete to cleanup by default, but
  1081 		// alternative cleanups can be specified
  1082 
  1083 		// We just want to free this one and not invoke the destructor
  1084 		LCleanedupPtr<CTicker, TPointerFree> t(static_cast<CTicker*>(User::AllocL(sizeof(CTicker))));
  1085 
  1086 		// Now User::Free() is called when t goes out of scope
  1087 		}
  1088 
  1089 		{
  1090 		// As well as the stock options, custom cleanup policies can
  1091 		// also be defined. See above for the definition of
  1092 		// TTickerZap.
  1093 		LCleanedupPtr<CTicker, TTickerZapStrategy> t(new(ELeave) CTicker);
  1094 
  1095 		// Now Zap() is called on the CTicker instance when t goes out of scope
  1096 		}
  1097 
  1098 		{
  1099 		// LCleanedupHandle is very similar in behaviour to
  1100 		// LCleanedupPtr, the main difference being that it can define
  1101 		// and contain its own instance of a handle rather than
  1102 		// being supplied one
  1103 		LCleanedupHandle<RTimer> t;
  1104 
  1105 		// Again, access to managed handle members is via ->
  1106 		t->CreateLocal() OR_LEAVE;
  1107 		t->Cancel();
  1108 
  1109 		// We can get a reference to the handle for passing to
  1110 		// functions using *
  1111 		RegisterTimer(*t);
  1112 
  1113 		// When the management object goes out of scope, either
  1114 		// normally or as the result of a leave, the managed object is
  1115 		// automatically cleanup by calling Close() on it
  1116 		}
  1117 
  1118 		{
  1119 		// LCleanedupHandle calls Close() by default, but alternative
  1120 		// cleanups can be specified
  1121 		
  1122 		// We want this RPointerArray cleanup with with
  1123 		// ResetAndDestroy instead of Close()
  1124 		LCleanedupHandle<RPointerArray<HBufC>, TResetAndDestroy> array;
  1125 		for (TInt i = 0; i < 10; ++i) 
  1126 			{
  1127 			array->AppendL(HBufC::NewL(5));
  1128 			}
  1129 
  1130 		// Now when array goes out of scope, ResetAndDestroy is called
  1131 		// to clean it up
  1132 		}
  1133 
  1134 		{
  1135 		// As well as the stock options, custom cleanup policies can
  1136 		// also be defined. See above for the definition of
  1137 		// TCancelClose.
  1138 		LCleanedupHandle<RTimer, TCancelClose> t;
  1139 		t->CreateLocal();
  1140 
  1141 		// Now Cancel() followed by Close() are called when t goes out
  1142 		// of scope
  1143 		}
  1144 
  1145 
  1146 		{
  1147 		// LCleanedupHandleRef calls Close() by default, but alternative
  1148 		// cleanups can be specified
  1149 		
  1150 		// We want this RPointerArray cleanup with with
  1151 		// ResetAndDestroy instead of Close()
  1152 		RPointerArray<HBufC> rar;
  1153 		// calls to functions that cannot leave here
  1154 		rar.Append(HBufC::NewL(5));
  1155 		rar.Append(HBufC::NewL(5));
  1156 
  1157 
  1158 		LCleanedupRef<RPointerArray<HBufC>, TResetAndDestroy> array(rar);
  1159 		// calls to functions that could leave here
  1160 		for (TInt i = 0; i < 10; ++i) 
  1161 			{
  1162 			array->AppendL(HBufC::NewL(5));
  1163 			}
  1164 
  1165 		// Now when array goes out of scope, ResetAndDestroy is called
  1166 		// to clean it up
  1167 		}
  1168 
  1169 		{
  1170 		// Never mix direct cleanup stack API calls with management
  1171 		// class use within the same function, because their
  1172 		// interaction can be confusing and counter intuitive. Avoid
  1173 		// the use of LC methods that leave objects on the cleanup
  1174 		// stack, and use L methods instead.
  1175 
  1176 		// If a badly-behaved API were to offer only an LC variant,
  1177 		// you would have to use it as follows
  1178 		HBufC* raw = HBufC::NewLC(5);
  1179 		// Must pop immediately to balance the cleanup stack, before
  1180 		// instantiating the manager
  1181 		CleanupStack::Pop(); 
  1182 		LCleanedupPtr<HBufC> wrapped(raw);
  1183 
  1184 		// Never do this:
  1185 		//LCleanedupPtr<HBufC> buf(HBufC::NewLC(5));
  1186 		//CleanupStack::Pop();
  1187 		// because the manager will be popped (having been pushed
  1188 		// last), not the raw buf pointer as you might have hoped
  1189 
  1190 		// A cleaner alternative may be to write your own L function
  1191 		// wrapper around the LC function supplied.
  1192 
  1193 		// Luckily this situation (an LC method without a
  1194 		// corresponding L method) is rare in practice.
  1195 		}
  1196 
  1197 		{
  1198 		// Although rarely used on Symbian OS, C++ arrays are
  1199 		// supported with a custom management class
  1200 		LCleanedupArray<CTicker> array(new CTicker[5]);
  1201 
  1202 		// The array is cleaned up with delete[] on scope exit
  1203 		}
  1204 
  1205 		{
  1206 		// Although most cases are best covered by applying custom
  1207 		// cleanup policies to the management classes already
  1208 		// described, there is also a general TCleanupItem style
  1209 		// cleanup option
  1210 		TAny* data = NULL; // But could be anything
  1211 		LCleanedupGuard guard1(BespokeCleanupFunction, data);
  1212 		// On scope exit BespokeCleanupFunction is called on data
  1213 
  1214 		LCleanedupGuard guard2(BespokeCleanupFunction, data);
  1215 		// But cleanup can also be disabled in this case, as follows
  1216 		guard2.Dismiss();
  1217 		}
  1218 		
  1219 		{
  1220 		TInt r =KErrNone;	
  1221 		LCleanedupHandle<RFs> managedFs;
  1222 		r = managedFs->Connect();
  1223 		if (r != KErrNone)
  1224 		 {
  1225 			User::Leave(r);
  1226 		 }
  1227 		//default cleanup strategy is to call RFs::Close() on scope exit
  1228 		}
  1229 		
  1230 		{
  1231 		LCleanedupHandle<RSimple, TFree> simple;
  1232 		simple->OpenL(23);
  1233 		//Specified cleanup strategy is to call RSimple::Free() on scope exit
  1234 		}
  1235 	
  1236 		//Because the DEFINE_CLEANUP_FUNCTION is defined above, the default
  1237 		//cleanup function for RSimple is RSimple::ReleaseData() rather than
  1238 		//RSimple::Close()
  1239 		{
  1240 		LCleanedupHandle<RSimple> simple;
  1241 		simple->OpenL(23);
  1242 		//Custom cleanup strategy is to call RSimple::ReleaseData() on scope exit
  1243 		}
  1244 		
  1245 		{
  1246 		RSimple simple;
  1247 		
  1248 		//The RSimple class above defines a static cleanup function
  1249 		//RSimple::Cleanup.
  1250 		LCleanedupGuard guard(RSimple::Cleanup, &simple);
  1251 
  1252 		simple.OpenL(10);
  1253 		
  1254 		//On scope exit RSimple::Cleanup() is called passing &simple
  1255 		}
  1256 	}
  1257 
  1258 void WalkthroughUsageL()
  1259 	{
  1260 	RFile file;
  1261 	
  1262 	test.Printf(_L("Size of RFile = %d"), sizeof(file));
  1263 	
  1264 	LCleanedupHandle<RFile> cFile;
  1265 	
  1266 	test.Printf(_L("Size of LCleanedupHandle<RFile> = %d"), sizeof(cFile));
  1267 	
  1268 	LCleanedupRef<RFile> crFile(file);
  1269 	
  1270 	test.Printf(_L("Size of LCleanedupRef<RFile> = %d"), sizeof(crFile));
  1271 	
  1272 	CTicker* tracker = new(ELeave) CTicker;
  1273 	//coverity[resource_leak]
  1274 	//As mentioned in the comment above any allocation failure is taken care of
  1275 	test.Printf(_L("Size of CTracker* = %d"), sizeof(tracker));
  1276 	
  1277 	LCleanedupPtr<CTicker> cTracker(tracker);
  1278 	
  1279 	test.Printf(_L("Size of LCleanedupHandle<RFile> = %d"), sizeof(LCleanedupPtr<CTicker>));
  1280 	}
  1281 
  1282 TInt TestL()
  1283 	{
  1284 	WalkthroughStringsL();
  1285 	WalkthroughManagedL();
  1286 	WalkthroughUsageL();
  1287 
  1288 	return KErrNone;
  1289 	}
  1290 
  1291 TInt E32Main()
  1292 	{
  1293 
  1294 	test.Start(_L("EUserHl Walkthrough"));
  1295 	test.Title();
  1296 
  1297 	CTrapCleanup* trapHandler=CTrapCleanup::New();
  1298 	test(trapHandler!=NULL);
  1299 	
  1300 	__UHEAP_MARK;
  1301 	
  1302 	TRAPD(status, TestL());
  1303 	
  1304 	__UHEAP_MARKEND;
  1305 
  1306 	if (status != KErrNone) test.Printf(_L("Error: %d\n"), status);
  1307 	
  1308 	test.Printf(_L("Test Completed with Error: %d"),status);
  1309 	
  1310 	return status;
  1311 	}
  1312 
  1313 
  1314 // eof