aboutsummaryrefslogtreecommitdiff
path: root/src/test/burn/TestBA/TestBA.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/burn/TestBA/TestBA.cs')
-rw-r--r--src/test/burn/TestBA/TestBA.cs613
1 files changed, 613 insertions, 0 deletions
diff --git a/src/test/burn/TestBA/TestBA.cs b/src/test/burn/TestBA/TestBA.cs
new file mode 100644
index 00000000..09378bc5
--- /dev/null
+++ b/src/test/burn/TestBA/TestBA.cs
@@ -0,0 +1,613 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Test.BA
4{
5 using System;
6 using System.Collections.Generic;
7 using System.IO;
8 using System.Linq;
9 using System.Threading;
10 using System.Windows.Forms;
11 using Microsoft.Win32;
12 using WixToolset.Mba.Core;
13
14 /// <summary>
15 /// A minimal UX used for testing.
16 /// </summary>
17 public class TestBA : BootstrapperApplication
18 {
19 private const string BurnBundleVersionVariable = "WixBundleVersion";
20
21 private Form dummyWindow;
22 private IntPtr windowHandle;
23 private LaunchAction action;
24 private ManualResetEvent wait;
25 private int result;
26
27 private string updateBundlePath;
28
29 private bool immediatelyQuit;
30 private bool quitAfterDetect;
31 private bool explicitlyElevateAndPlanFromOnElevateBegin;
32 private int redetectRemaining;
33 private int sleepDuringCache;
34 private int cancelCacheAtProgress;
35 private int sleepDuringExecute;
36 private int cancelExecuteAtProgress;
37 private string cancelExecuteActionName;
38 private int cancelOnProgressAtProgress;
39 private int retryExecuteFilesInUse;
40
41 private IBootstrapperCommand Command { get; }
42
43 private IEngine Engine => this.engine;
44
45 /// <summary>
46 /// Initializes test user experience.
47 /// </summary>
48 public TestBA(IEngine engine, IBootstrapperCommand bootstrapperCommand)
49 : base(engine)
50 {
51 this.Command = bootstrapperCommand;
52 this.wait = new ManualResetEvent(false);
53 }
54
55 /// <summary>
56 /// Get the version of the install.
57 /// </summary>
58 public string Version { get; private set; }
59
60 /// <summary>
61 /// Indicates if DetectUpdate found a newer version to update.
62 /// </summary>
63 private bool UpdateAvailable { get; set; }
64
65 /// <summary>
66 /// UI Thread entry point for TestUX.
67 /// </summary>
68 protected override void OnStartup(StartupEventArgs args)
69 {
70 string immediatelyQuit = this.ReadPackageAction(null, "ImmediatelyQuit");
71 if (!String.IsNullOrEmpty(immediatelyQuit) && Boolean.TryParse(immediatelyQuit, out this.immediatelyQuit) && this.immediatelyQuit)
72 {
73 this.Engine.Quit(0);
74 return;
75 }
76
77 base.OnStartup(args);
78
79 this.action = this.Command.Action;
80 this.TestVariables();
81
82 this.Version = this.engine.GetVariableVersion(BurnBundleVersionVariable);
83 this.Log("Version: {0}", this.Version);
84
85 List<string> verifyArguments = this.ReadVerifyArguments();
86
87 foreach (string arg in this.Command.CommandLineArgs)
88 {
89 // If we're not in the update already, process the updatebundle.
90 if (this.Command.Relation != RelationType.Update && arg.StartsWith("-updatebundle:", StringComparison.OrdinalIgnoreCase))
91 {
92 this.updateBundlePath = arg.Substring(14);
93 FileInfo info = new FileInfo(this.updateBundlePath);
94 this.Engine.SetUpdate(this.updateBundlePath, null, info.Length, UpdateHashType.None, null);
95 this.UpdateAvailable = true;
96 this.action = LaunchAction.UpdateReplaceEmbedded;
97 }
98 else if (this.Command.Relation != RelationType.Update && arg.StartsWith("-checkupdate", StringComparison.OrdinalIgnoreCase))
99 {
100 this.action = LaunchAction.UpdateReplace;
101 }
102
103 verifyArguments.Remove(arg);
104 }
105 this.Log("Action: {0}", this.action);
106
107 // If there are any verification arguments left, error out.
108 if (0 < verifyArguments.Count)
109 {
110 foreach (string expectedArg in verifyArguments)
111 {
112 this.Log("Failure. Expected command-line to have argument: {0}", expectedArg);
113 }
114
115 this.Engine.Quit(-1);
116 return;
117 }
118
119 int redetectCount;
120 string redetect = this.ReadPackageAction(null, "RedetectCount");
121 if (String.IsNullOrEmpty(redetect) || !Int32.TryParse(redetect, out redetectCount))
122 {
123 redetectCount = 0;
124 }
125
126 string explicitlyElevateAndPlanFromOnElevateBegin = this.ReadPackageAction(null, "ExplicitlyElevateAndPlanFromOnElevateBegin");
127 if (String.IsNullOrEmpty(explicitlyElevateAndPlanFromOnElevateBegin) || !Boolean.TryParse(explicitlyElevateAndPlanFromOnElevateBegin, out this.explicitlyElevateAndPlanFromOnElevateBegin))
128 {
129 this.explicitlyElevateAndPlanFromOnElevateBegin = false;
130 }
131
132 string quitAfterDetect = this.ReadPackageAction(null, "QuitAfterDetect");
133 if (String.IsNullOrEmpty(quitAfterDetect) || !Boolean.TryParse(quitAfterDetect, out this.quitAfterDetect))
134 {
135 this.quitAfterDetect = false;
136 }
137
138 this.wait.WaitOne();
139
140 this.redetectRemaining = redetectCount;
141 for (int i = -1; i < redetectCount; i++)
142 {
143 this.Engine.Detect(this.windowHandle);
144 }
145 }
146
147 protected override void Run()
148 {
149 this.dummyWindow = new Form();
150 this.windowHandle = this.dummyWindow.Handle;
151
152 this.Log("Running TestBA application");
153 this.wait.Set();
154 Application.Run();
155 }
156
157 private void ShutdownUiThread()
158 {
159 if (this.dummyWindow != null)
160 {
161 this.dummyWindow.Invoke(new Action(Application.ExitThread));
162 this.dummyWindow.Dispose();
163 }
164
165 this.Engine.Quit(this.result & 0xFFFF); // return plain old Win32 error, not HRESULT.
166 }
167
168 protected override void OnDetectUpdateBegin(DetectUpdateBeginEventArgs args)
169 {
170 this.Log("OnDetectUpdateBegin");
171 if (LaunchAction.UpdateReplaceEmbedded == this.action || LaunchAction.UpdateReplace == this.action)
172 {
173 args.Skip = false;
174 }
175 }
176
177 protected override void OnDetectUpdate(DetectUpdateEventArgs e)
178 {
179 // The list of updates is sorted in descending version, so the first callback should be the largest update available.
180 // This update should be either larger than ours (so we are out of date), the same as ours (so we are current)
181 // or smaller than ours (we have a private build).
182 // Enumerate all of the updates anyway in case something's broken.
183 this.Log(String.Format("Potential update v{0} from '{1}'; current version: v{2}", e.Version, e.UpdateLocation, this.Version));
184 if (!this.UpdateAvailable && this.Engine.CompareVersions(e.Version, this.Version) > 0)
185 {
186 this.Log(String.Format("Selected update v{0}", e.Version));
187 this.Engine.SetUpdate(null, e.UpdateLocation, e.Size, UpdateHashType.None, null);
188 this.UpdateAvailable = true;
189 }
190 }
191
192 protected override void OnDetectUpdateComplete(DetectUpdateCompleteEventArgs e)
193 {
194 this.Log("OnDetectUpdateComplete");
195
196 // Failed to process an update, allow the existing bundle to still install.
197 if (!Hresult.Succeeded(e.Status))
198 {
199 this.Log(String.Format("Failed to locate an update, status of 0x{0:X8}, updates disabled.", e.Status));
200 e.IgnoreError = true; // But continue on...
201 }
202 }
203
204 protected override void OnDetectComplete(DetectCompleteEventArgs args)
205 {
206 this.result = args.Status;
207
208 if (Hresult.Succeeded(this.result) &&
209 (this.UpdateAvailable || LaunchAction.UpdateReplaceEmbedded != this.action && LaunchAction.UpdateReplace != this.action))
210 {
211 if (this.redetectRemaining > 0)
212 {
213 this.Log("Completed detection phase: {0} re-runs remaining", this.redetectRemaining--);
214 }
215 else if (this.quitAfterDetect)
216 {
217 this.ShutdownUiThread();
218 }
219 else if (this.explicitlyElevateAndPlanFromOnElevateBegin)
220 {
221 this.Engine.Elevate(this.windowHandle);
222 }
223 else
224 {
225 this.Engine.Plan(this.action);
226 }
227 }
228 else
229 {
230 this.ShutdownUiThread();
231 }
232 }
233
234 protected override void OnDetectRelatedBundle(DetectRelatedBundleEventArgs args)
235 {
236 this.Log("OnDetectRelatedBundle() - id: {0}, missing from cache: {1}", args.ProductCode, args.MissingFromCache);
237 }
238
239 protected override void OnElevateBegin(ElevateBeginEventArgs args)
240 {
241 if (this.explicitlyElevateAndPlanFromOnElevateBegin)
242 {
243 this.Engine.Plan(this.action);
244
245 // Simulate showing some UI since these tests won't actually show the UAC prompt.
246 MessagePump.ProcessMessages(10);
247 }
248 }
249
250 protected override void OnPlanPackageBegin(PlanPackageBeginEventArgs args)
251 {
252 RequestState state;
253 string action = this.ReadPackageAction(args.PackageId, "Requested");
254 if (TryParseEnum<RequestState>(action, out state))
255 {
256 args.State = state;
257 }
258 }
259
260 protected override void OnPlanPatchTarget(PlanPatchTargetEventArgs args)
261 {
262 RequestState state;
263 string action = this.ReadPackageAction(args.PackageId, "Requested");
264 if (TryParseEnum<RequestState>(action, out state))
265 {
266 args.State = state;
267 }
268 }
269
270 protected override void OnPlanMsiFeature(PlanMsiFeatureEventArgs args)
271 {
272 FeatureState state;
273 string action = this.ReadFeatureAction(args.PackageId, args.FeatureId, "Requested");
274 if (TryParseEnum<FeatureState>(action, out state))
275 {
276 args.State = state;
277 }
278 }
279
280 protected override void OnPlanComplete(PlanCompleteEventArgs args)
281 {
282 this.result = args.Status;
283 if (Hresult.Succeeded(this.result))
284 {
285 this.Engine.Apply(this.windowHandle);
286 }
287 else
288 {
289 this.ShutdownUiThread();
290 }
291 }
292
293 protected override void OnCachePackageBegin(CachePackageBeginEventArgs args)
294 {
295 this.Log("OnCachePackageBegin() - package: {0}, payloads to cache: {1}", args.PackageId, args.CachePayloads);
296
297 string slowProgress = this.ReadPackageAction(args.PackageId, "SlowCache");
298 if (String.IsNullOrEmpty(slowProgress) || !Int32.TryParse(slowProgress, out this.sleepDuringCache))
299 {
300 this.sleepDuringCache = 0;
301 }
302 else
303 {
304 this.Log(" SlowCache: {0}", this.sleepDuringCache);
305 }
306
307 string cancelCache = this.ReadPackageAction(args.PackageId, "CancelCacheAtProgress");
308 if (String.IsNullOrEmpty(cancelCache) || !Int32.TryParse(cancelCache, out this.cancelCacheAtProgress))
309 {
310 this.cancelCacheAtProgress = -1;
311 }
312 else
313 {
314 this.Log(" CancelCacheAtProgress: {0}", this.cancelCacheAtProgress);
315 }
316 }
317
318 protected override void OnCacheAcquireProgress(CacheAcquireProgressEventArgs args)
319 {
320 this.Log("OnCacheAcquireProgress() - container/package: {0}, payload: {1}, progress: {2}, total: {3}, overall progress: {4}%", args.PackageOrContainerId, args.PayloadId, args.Progress, args.Total, args.OverallPercentage);
321
322 if (this.cancelCacheAtProgress >= 0 && this.cancelCacheAtProgress <= args.Progress)
323 {
324 args.Cancel = true;
325 this.Log("OnCacheAcquireProgress(cancel)");
326 }
327 else if (this.sleepDuringCache > 0)
328 {
329 this.Log("OnCacheAcquireProgress(sleep {0})", this.sleepDuringCache);
330 Thread.Sleep(this.sleepDuringCache);
331 }
332 }
333
334 protected override void OnCacheContainerOrPayloadVerifyProgress(CacheContainerOrPayloadVerifyProgressEventArgs args)
335 {
336 this.Log("OnCacheContainerOrPayloadVerifyProgress() - container/package: {0}, payload: {1}, progress: {2}, total: {3}, overall progress: {4}%", args.PackageOrContainerId, args.PayloadId, args.Progress, args.Total, args.OverallPercentage);
337 }
338
339 protected override void OnCachePayloadExtractProgress(CachePayloadExtractProgressEventArgs args)
340 {
341 this.Log("OnCachePayloadExtractProgress() - container/package: {0}, payload: {1}, progress: {2}, total: {3}, overall progress: {4}%", args.PackageOrContainerId, args.PayloadId, args.Progress, args.Total, args.OverallPercentage);
342 }
343
344 protected override void OnCacheVerifyProgress(CacheVerifyProgressEventArgs args)
345 {
346 this.Log("OnCacheVerifyProgress() - container/package: {0}, payload: {1}, progress: {2}, total: {3}, overall progress: {4}%, step: {5}", args.PackageOrContainerId, args.PayloadId, args.Progress, args.Total, args.OverallPercentage, args.Step);
347 }
348
349 protected override void OnExecutePackageBegin(ExecutePackageBeginEventArgs args)
350 {
351 this.Log("OnExecutePackageBegin() - package: {0}, rollback: {1}", args.PackageId, !args.ShouldExecute);
352
353 string slowProgress = this.ReadPackageAction(args.PackageId, "SlowExecute");
354 if (String.IsNullOrEmpty(slowProgress) || !Int32.TryParse(slowProgress, out this.sleepDuringExecute))
355 {
356 this.sleepDuringExecute = 0;
357 }
358 else
359 {
360 this.Log(" SlowExecute: {0}", this.sleepDuringExecute);
361 }
362
363 string cancelExecute = this.ReadPackageAction(args.PackageId, "CancelExecuteAtProgress");
364 if (String.IsNullOrEmpty(cancelExecute) || !Int32.TryParse(cancelExecute, out this.cancelExecuteAtProgress))
365 {
366 this.cancelExecuteAtProgress = -1;
367 }
368 else
369 {
370 this.Log(" CancelExecuteAtProgress: {0}", this.cancelExecuteAtProgress);
371 }
372
373 this.cancelExecuteActionName = this.ReadPackageAction(args.PackageId, "CancelExecuteAtActionStart");
374 if (!String.IsNullOrEmpty(this.cancelExecuteActionName))
375 {
376 this.Log(" CancelExecuteAtActionState: {0}", this.cancelExecuteActionName);
377 }
378
379 string cancelOnProgressAtProgress = this.ReadPackageAction(args.PackageId, "CancelOnProgressAtProgress");
380 if (String.IsNullOrEmpty(cancelOnProgressAtProgress) || !Int32.TryParse(cancelOnProgressAtProgress, out this.cancelOnProgressAtProgress))
381 {
382 this.cancelOnProgressAtProgress = -1;
383 }
384 else
385 {
386 this.Log(" CancelOnProgressAtProgress: {0}", this.cancelOnProgressAtProgress);
387 }
388
389 string retryBeforeCancel = this.ReadPackageAction(args.PackageId, "RetryExecuteFilesInUse");
390 if (String.IsNullOrEmpty(retryBeforeCancel) || !Int32.TryParse(retryBeforeCancel, out this.retryExecuteFilesInUse))
391 {
392 this.retryExecuteFilesInUse = 0;
393 }
394 else
395 {
396 this.Log(" RetryExecuteFilesInUse: {0}", this.retryExecuteFilesInUse);
397 }
398 }
399
400 protected override void OnExecuteFilesInUse(ExecuteFilesInUseEventArgs args)
401 {
402 this.Log("OnExecuteFilesInUse() - package: {0}, retries remaining: {1}, data: {2}", args.PackageId, this.retryExecuteFilesInUse, String.Join(", ", args.Files.ToArray()));
403
404 if (this.retryExecuteFilesInUse > 0)
405 {
406 --this.retryExecuteFilesInUse;
407 args.Result = Result.Retry;
408 }
409 else
410 {
411 args.Result = Result.Abort;
412 }
413 }
414
415 protected override void OnExecuteMsiMessage(ExecuteMsiMessageEventArgs args)
416 {
417 this.Log("OnExecuteMsiMessage() - MessageType: {0}, Message: {1}, Data: '{2}'", args.MessageType, args.Message, String.Join("','", args.Data.ToArray()));
418
419 if (!String.IsNullOrEmpty(this.cancelExecuteActionName) && args.MessageType == InstallMessage.ActionStart &&
420 args.Data.Count > 0 && args.Data[0] == this.cancelExecuteActionName)
421 {
422 this.Log("OnExecuteMsiMessage(cancelNextProgress)");
423 this.cancelExecuteAtProgress = 0;
424 }
425 }
426
427 protected override void OnExecuteProgress(ExecuteProgressEventArgs args)
428 {
429 this.Log("OnExecuteProgress() - package: {0}, progress: {1}%, overall progress: {2}%", args.PackageId, args.ProgressPercentage, args.OverallPercentage);
430
431 if (this.cancelExecuteAtProgress >= 0 && this.cancelExecuteAtProgress <= args.ProgressPercentage)
432 {
433 args.Cancel = true;
434 this.Log("OnExecuteProgress(cancel)");
435 }
436 else if (this.sleepDuringExecute > 0)
437 {
438 this.Log("OnExecuteProgress(sleep {0})", this.sleepDuringExecute);
439 Thread.Sleep(this.sleepDuringExecute);
440 }
441 }
442
443 protected override void OnExecutePatchTarget(ExecutePatchTargetEventArgs args)
444 {
445 this.Log("OnExecutePatchTarget - Patch Package: {0}, Target Product Code: {1}", args.PackageId, args.TargetProductCode);
446 }
447
448 protected override void OnProgress(ProgressEventArgs args)
449 {
450 this.Log("OnProgress() - progress: {0}%, overall progress: {1}%", args.ProgressPercentage, args.OverallPercentage);
451 if (this.Command.Display == Display.Embedded)
452 {
453 this.Engine.SendEmbeddedProgress(args.ProgressPercentage, args.OverallPercentage);
454 }
455
456 if (this.cancelOnProgressAtProgress >= 0 && this.cancelOnProgressAtProgress <= args.OverallPercentage)
457 {
458 args.Cancel = true;
459 this.Log("OnProgress(cancel)");
460 }
461 }
462
463 protected override void OnApplyBegin(ApplyBeginEventArgs args)
464 {
465 this.cancelOnProgressAtProgress = -1;
466 this.cancelExecuteAtProgress = -1;
467 this.cancelCacheAtProgress = -1;
468 }
469
470 protected override void OnApplyComplete(ApplyCompleteEventArgs args)
471 {
472 // Output what the privileges are now.
473 this.Log("After elevation: WixBundleElevated = {0}", this.Engine.GetVariableNumeric("WixBundleElevated"));
474
475 this.result = args.Status;
476 this.ShutdownUiThread();
477 }
478
479 protected override void OnSystemShutdown(SystemShutdownEventArgs args)
480 {
481 // Always prevent shutdown.
482 this.Log("Disallowed system request to shut down the bootstrapper application.");
483 args.Cancel = true;
484
485 this.ShutdownUiThread();
486 }
487
488 private void TestVariables()
489 {
490 // First make sure we can check and get standard variables of each type.
491 {
492 string value = null;
493 if (this.Engine.ContainsVariable("WindowsFolder"))
494 {
495 value = this.Engine.GetVariableString("WindowsFolder");
496 this.Engine.Log(LogLevel.Verbose, "TEST: Successfully retrieved a string variable: WindowsFolder");
497 }
498 else
499 {
500 throw new Exception("Engine did not define a standard variable: WindowsFolder");
501 }
502 }
503
504 {
505 long value = 0;
506 if (this.Engine.ContainsVariable("NTProductType"))
507 {
508 value = this.Engine.GetVariableNumeric("NTProductType");
509 this.Engine.Log(LogLevel.Verbose, "TEST: Successfully retrieved a numeric variable: NTProductType");
510 }
511 else
512 {
513 throw new Exception("Engine did not define a standard variable: NTProductType");
514 }
515 }
516
517 {
518 string value = null;
519 if (this.Engine.ContainsVariable("VersionMsi"))
520 {
521 value = this.Engine.GetVariableVersion("VersionMsi");
522 this.Engine.Log(LogLevel.Verbose, "TEST: Successfully retrieved a version variable: VersionMsi");
523 }
524 else
525 {
526 throw new Exception("Engine did not define a standard variable: VersionMsi");
527 }
528 }
529
530 // Now validate that Contians returns false for non-existant variables of each type.
531 if (this.Engine.ContainsVariable("TestStringVariableShouldNotExist"))
532 {
533 throw new Exception("Engine defined a variable that should not exist: TestStringVariableShouldNotExist");
534 }
535 else
536 {
537 this.Engine.Log(LogLevel.Verbose, "TEST: Successfully checked for non-existent string variable: TestStringVariableShouldNotExist");
538 }
539
540 if (this.Engine.ContainsVariable("TestNumericVariableShouldNotExist"))
541 {
542 throw new Exception("Engine defined a variable that should not exist: TestNumericVariableShouldNotExist");
543 }
544 else
545 {
546 this.Engine.Log(LogLevel.Verbose, "TEST: Successfully checked for non-existent numeric variable: TestNumericVariableShouldNotExist");
547 }
548
549 if (this.Engine.ContainsVariable("TestVersionVariableShouldNotExist"))
550 {
551 throw new Exception("Engine defined a variable that should not exist: TestVersionVariableShouldNotExist");
552 }
553 else
554 {
555 this.Engine.Log(LogLevel.Verbose, "TEST: Successfully checked for non-existent version variable: TestVersionVariableShouldNotExist");
556 }
557
558 // Output what the initially run privileges were.
559 this.Engine.Log(LogLevel.Verbose, String.Format("TEST: WixBundleElevated = {0}", this.Engine.GetVariableNumeric("WixBundleElevated")));
560 }
561
562 private void Log(string format, params object[] args)
563 {
564 string relation = this.Command.Relation != RelationType.None ? String.Concat(" (", this.Command.Relation.ToString().ToLowerInvariant(), ")") : String.Empty;
565 string message = String.Format(format, args);
566
567 this.Engine.Log(LogLevel.Standard, String.Concat("TESTBA", relation, ": ", message));
568 }
569
570 private List<string> ReadVerifyArguments()
571 {
572 string testName = this.Engine.GetVariableString("TestGroupName");
573 using (RegistryKey testKey = Registry.LocalMachine.OpenSubKey(String.Format(@"Software\WiX\Tests\TestBAControl\{0}", testName)))
574 {
575 string verifyArguments = testKey == null ? null : testKey.GetValue("VerifyArguments") as string;
576 return verifyArguments == null ? new List<string>() : new List<string>(verifyArguments.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
577 }
578 }
579
580 private string ReadPackageAction(string packageId, string state)
581 {
582 string testName = this.Engine.GetVariableString("TestGroupName");
583 using (RegistryKey testKey = Registry.LocalMachine.OpenSubKey(String.Format(@"Software\WiX\Tests\TestBAControl\{0}\{1}", testName, String.IsNullOrEmpty(packageId) ? String.Empty : packageId)))
584 {
585 return testKey == null ? null : testKey.GetValue(state) as string;
586 }
587 }
588
589 private string ReadFeatureAction(string packageId, string featureId, string state)
590 {
591 string testName = this.Engine.GetVariableString("TestGroupName");
592 using (RegistryKey testKey = Registry.LocalMachine.OpenSubKey(String.Format(@"Software\WiX\Tests\TestBAControl\{0}\{1}", testName, packageId)))
593 {
594 string registryName = String.Concat(featureId, state);
595 return testKey == null ? null : testKey.GetValue(registryName) as string;
596 }
597 }
598
599 private static bool TryParseEnum<T>(string value, out T t)
600 {
601 try
602 {
603 t = (T)Enum.Parse(typeof(T), value, true);
604 return true;
605 }
606 catch (ArgumentException) { }
607 catch (OverflowException) { }
608
609 t = default(T);
610 return false;
611 }
612 }
613}