lowlevellibsandfws/genericusabilitylib/example/src/euserhl_walkthrough.cpp
changeset 0 e4d67989cc36
child 44 97b0fb8a2cc2
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     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 		LCleanedupHandle<RFs> managedFs;
       
  1221 		managedFs->Connect();
       
  1222 		//default cleanup strategy is to call RFs::Close() on scope exit
       
  1223 		}
       
  1224 		
       
  1225 		{
       
  1226 		LCleanedupHandle<RSimple, TFree> simple;
       
  1227 		simple->OpenL(23);
       
  1228 		//Specified cleanup strategy is to call RSimple::Free() on scope exit
       
  1229 		}
       
  1230 	
       
  1231 		//Because the DEFINE_CLEANUP_FUNCTION is defined above, the default
       
  1232 		//cleanup function for RSimple is RSimple::ReleaseData() rather than
       
  1233 		//RSimple::Close()
       
  1234 		{
       
  1235 		LCleanedupHandle<RSimple> simple;
       
  1236 		simple->OpenL(23);
       
  1237 		//Custom cleanup strategy is to call RSimple::ReleaseData() on scope exit
       
  1238 		}
       
  1239 		
       
  1240 		{
       
  1241 		RSimple simple;
       
  1242 		
       
  1243 		//The RSimple class above defines a static cleanup function
       
  1244 		//RSimple::Cleanup.
       
  1245 		LCleanedupGuard guard(RSimple::Cleanup, &simple);
       
  1246 
       
  1247 		simple.OpenL(10);
       
  1248 		
       
  1249 		//On scope exit RSimple::Cleanup() is called passing &simple
       
  1250 		}
       
  1251 	}
       
  1252 
       
  1253 void WalkthroughUsageL()
       
  1254 	{
       
  1255 	RFile file;
       
  1256 	
       
  1257 	test.Printf(_L("Size of RFile = %d"), sizeof(file));
       
  1258 	
       
  1259 	LCleanedupHandle<RFile> cFile;
       
  1260 	
       
  1261 	test.Printf(_L("Size of LCleanedupHandle<RFile> = %d"), sizeof(cFile));
       
  1262 	
       
  1263 	LCleanedupRef<RFile> crFile(file);
       
  1264 	
       
  1265 	test.Printf(_L("Size of LCleanedupRef<RFile> = %d"), sizeof(crFile));
       
  1266 	
       
  1267 	CTicker* tracker = new(ELeave) CTicker;
       
  1268 	//coverity[resource_leak]
       
  1269 	//As mentioned in the comment above any allocation failure is taken care of
       
  1270 	test.Printf(_L("Size of CTracker* = %d"), sizeof(tracker));
       
  1271 	
       
  1272 	LCleanedupPtr<CTicker> cTracker(tracker);
       
  1273 	
       
  1274 	test.Printf(_L("Size of LCleanedupHandle<RFile> = %d"), sizeof(LCleanedupPtr<CTicker>));
       
  1275 	}
       
  1276 
       
  1277 TInt TestL()
       
  1278 	{
       
  1279 	WalkthroughStringsL();
       
  1280 	WalkthroughManagedL();
       
  1281 	WalkthroughUsageL();
       
  1282 
       
  1283 	return KErrNone;
       
  1284 	}
       
  1285 
       
  1286 TInt E32Main()
       
  1287 	{
       
  1288 
       
  1289 	test.Start(_L("EUserHl Walkthrough"));
       
  1290 	test.Title();
       
  1291 
       
  1292 	CTrapCleanup* trapHandler=CTrapCleanup::New();
       
  1293 	test(trapHandler!=NULL);
       
  1294 	
       
  1295 	__UHEAP_MARK;
       
  1296 	
       
  1297 	TRAPD(status, TestL());
       
  1298 	
       
  1299 	__UHEAP_MARKEND;
       
  1300 
       
  1301 	if (status != KErrNone) test.Printf(_L("Error: %d\n"), status);
       
  1302 	
       
  1303 	test.Printf(_L("Test Completed with Error: %d"),status);
       
  1304 	
       
  1305 	return status;
       
  1306 	}
       
  1307 
       
  1308 
       
  1309 // eof