Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Refactor native library pre-loading code to be more flexible. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | refactorNativeLibraryPreLoader |
Files: | files | file ages | folders |
SHA1: |
77a0e66f105534c8cc6109de764b6403 |
User & Date: | mistachkin 2013-12-26 04:01:18 |
Context
2013-12-26
| ||
23:48 | More work-in-progress on refactoring the native library pre-loader. check-in: 60011bd9e5 user: mistachkin tags: refactorNativeLibraryPreLoader | |
04:01 | Refactor native library pre-loading code to be more flexible. check-in: 77a0e66f10 user: mistachkin tags: refactorNativeLibraryPreLoader | |
00:57 | Fix HTML entity escaping in the environment variable documentation page. check-in: 2f18d24bcc user: mistachkin tags: trunk | |
Changes
Changes to System.Data.SQLite/SQLiteConnection.cs.
1619 1619 int n; 1620 1620 SortedList<string, string> ls = new SortedList<string, string>(StringComparer.OrdinalIgnoreCase); 1621 1621 1622 1622 // First split into semi-colon delimited values. 1623 1623 string error = null; 1624 1624 string[] arParts; 1625 1625 1626 -#if !PLATFORM_COMPACTFRAMEWORK 1627 - if (Environment.GetEnvironmentVariable("No_SQLiteConnectionNewParser") != null) 1626 + if (UnsafeNativeMethods.GetVariableValue("No_SQLiteConnectionNewParser") != null) 1628 1627 arParts = SQLiteConvert.Split(s, ';'); 1629 1628 else 1630 -#endif 1631 1629 arParts = SQLiteConvert.NewSplit(s, ';', true, ref error); 1632 1630 1633 1631 if (arParts == null) 1634 1632 { 1635 1633 throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, 1636 1634 "Invalid ConnectionString format, cannot parse: {0}", (error != null) ? 1637 1635 error : "could not split connection string into properties"));
Changes to System.Data.SQLite/SQLiteFunction.cs.
653 653 try 654 654 { 655 655 #if !PLATFORM_COMPACTFRAMEWORK 656 656 // 657 657 // NOTE: If the "No_SQLiteFunctions" environment variable is set, 658 658 // skip all our special code and simply return. 659 659 // 660 - if (Environment.GetEnvironmentVariable("No_SQLiteFunctions") != null) 660 + if (UnsafeNativeMethods.GetVariableValue("No_SQLiteFunctions") != null) 661 661 return; 662 662 663 663 SQLiteFunctionAttribute at; 664 664 System.Reflection.Assembly[] arAssemblies = System.AppDomain.CurrentDomain.GetAssemblies(); 665 665 int w = arAssemblies.Length; 666 666 System.Reflection.AssemblyName sqlite = System.Reflection.Assembly.GetExecutingAssembly().GetName(); 667 667
Changes to System.Data.SQLite/SQLiteLog.cs.
148 148 // is loaded per-process and has only one logging callback, 149 149 // not one per-AppDomain, which it knows nothing about), 150 150 // prevent all non-default AppDomains from registering a 151 151 // log handler unless the "Force_SQLiteLog" environment 152 152 // variable is used to manually override this safety check. 153 153 // 154 154 if (!AppDomain.CurrentDomain.IsDefaultAppDomain() && 155 - Environment.GetEnvironmentVariable("Force_SQLiteLog") == null) 155 + UnsafeNativeMethods.GetVariableValue("Force_SQLiteLog") == null) 156 156 { 157 157 return; 158 158 } 159 159 #endif 160 160 161 161 lock (syncRoot) 162 162 {
Changes to System.Data.SQLite/UnsafeNativeMethods.cs.
25 25 #endif 26 26 27 27 using System.Runtime.InteropServices; 28 28 29 29 #if !PLATFORM_COMPACTFRAMEWORK || COUNT_HANDLE 30 30 using System.Threading; 31 31 #endif 32 + 33 + using System.Xml; 32 34 33 35 #if !PLATFORM_COMPACTFRAMEWORK && !DEBUG 34 36 [SuppressUnmanagedCodeSecurity] 35 37 #endif 36 38 internal static class UnsafeNativeMethods 37 39 { 38 40 #region Critical Handle Counts (Debug Build Only) ................................................................................ 66 68 #if SQLITE_STANDARD || USE_INTEROP_DLL || PLATFORM_COMPACTFRAMEWORK 67 69 68 70 // 69 71 // NOTE: Only compile in the native library pre-load code if the feature 70 72 // has been enabled for this build. 71 73 // 72 74 #if PRELOAD_NATIVE_LIBRARY 73 -#if !PLATFORM_COMPACTFRAMEWORK 74 75 /// <summary> 75 76 /// The name of the environment variable containing the processor 76 77 /// architecture of the current process. 77 78 /// </summary> 78 79 private static readonly string PROCESSOR_ARCHITECTURE = 79 80 "PROCESSOR_ARCHITECTURE"; 80 -#endif 81 81 82 82 ///////////////////////////////////////////////////////////////////////// 83 83 84 84 private static readonly string DllFileExtension = ".dll"; 85 + 86 + ///////////////////////////////////////////////////////////////////////// 87 + 88 + private static readonly string XmlConfigurationFileName = 89 + typeof(UnsafeNativeMethods).Namespace + ".config"; 85 90 86 91 ///////////////////////////////////////////////////////////////////////// 87 92 /// <summary> 88 93 /// This is the P/Invoke method that wraps the native Win32 LoadLibrary 89 94 /// function. See the MSDN documentation for full details on what it 90 95 /// does. 91 96 /// </summary> ................................................................................ 197 202 ///////////////////////////////////////////////////////////////////////// 198 203 /// <summary> 199 204 /// Attempts to initialize this class by pre-loading the native SQLite 200 205 /// library for the processor architecture of the current process. 201 206 /// </summary> 202 207 internal static void Initialize() 203 208 { 204 -#if !PLATFORM_COMPACTFRAMEWORK 205 209 // 206 210 // NOTE: If the "No_PreLoadSQLite" environment variable is set (to 207 211 // anything), skip all our special code and simply return. 208 212 // 209 - if (Environment.GetEnvironmentVariable("No_PreLoadSQLite") != null) 213 + if (GetVariableValue("No_PreLoadSQLite") != null) 210 214 return; 211 -#endif 212 215 213 216 lock (staticSyncRoot) 214 217 { 215 218 // 216 219 // TODO: Make sure this list is updated if the supported 217 220 // processor architecture names and/or platform names 218 221 // changes. ................................................................................ 244 247 if (_SQLiteModule == IntPtr.Zero) 245 248 _SQLiteModule = PreLoadSQLiteDll(null, null); 246 249 } 247 250 } 248 251 249 252 ///////////////////////////////////////////////////////////////////////// 250 253 /// <summary> 254 + /// 255 + /// </summary> 256 + /// <returns> 257 + /// 258 + /// </returns> 259 + private static string GetXmlConfigurationFileName() 260 + { 261 + string directory; 262 + string fileName; 263 + 264 +#if !PLATFORM_COMPACTFRAMEWORK 265 + directory = AppDomain.CurrentDomain.BaseDirectory; 266 + fileName = Path.Combine(directory, XmlConfigurationFileName); 267 + 268 + if (File.Exists(fileName)) 269 + return fileName; 270 +#endif 271 + 272 + directory = GetAssemblyDirectory(); 273 + fileName = Path.Combine(directory, XmlConfigurationFileName); 274 + 275 + if (File.Exists(fileName)) 276 + return fileName; 277 + 278 + return null; 279 + } 280 + 281 + ///////////////////////////////////////////////////////////////////////// 282 + /// <summary> 283 + /// Queries and returns the value of the specified "configuration" 284 + /// variable, using the XML configuration file and/or the environment 285 + /// variables for the current process and/or the current system, when 286 + /// available. 287 + /// </summary> 288 + /// <param name="name"> 289 + /// The name of the configuration variable. 290 + /// </param> 291 + /// <returns> 292 + /// The value of the configuration variable -OR- null if it cannot be 293 + /// determined. By default, references to existing environment will 294 + /// be expanded within the returned value unless either the "No_Expand" 295 + /// or "No_Expand_<paramref name="name" />" environment variables are 296 + /// set. 297 + /// </returns> 298 + internal static string GetVariableValue( 299 + string name 300 + ) 301 + { 302 + string value = null; 303 + 304 + if (name == null) 305 + return value; 306 + 307 +#if !PLATFORM_COMPACTFRAMEWORK 308 + bool expand = true; 309 + 310 + if (Environment.GetEnvironmentVariable("No_Expand") != null) 311 + { 312 + expand = false; 313 + } 314 + else if (Environment.GetEnvironmentVariable(String.Format( 315 + "No_Expand_{0}", name)) != null) 316 + { 317 + expand = false; 318 + } 319 + 320 + value = Environment.GetEnvironmentVariable(name); 321 + 322 + if (expand && !String.IsNullOrEmpty(value)) 323 + value = Environment.ExpandEnvironmentVariables(value); 324 + 325 + if (value != null) 326 + return value; 327 +#endif 328 + 329 + try 330 + { 331 + string fileName = GetXmlConfigurationFileName(); 332 + 333 + if (fileName == null) 334 + return value; 335 + 336 + XmlDocument document = new XmlDocument(); 337 + 338 + document.Load(fileName); 339 + 340 + XmlElement element = document.SelectSingleNode(String.Format( 341 + "/configuration/appSettings/add[@key='{0}']")) as XmlElement; 342 + 343 + if (element != null) 344 + { 345 + value = element.GetAttribute("value"); 346 + 347 + if (String.IsNullOrEmpty(value)) 348 + value = null; 349 +#if !PLATFORM_COMPACTFRAMEWORK 350 + else if (expand) 351 + value = Environment.ExpandEnvironmentVariables(value); 352 +#endif 353 + } 354 + } 355 +#if !NET_COMPACT_20 && TRACE_PRELOAD 356 + catch (Exception e) 357 +#else 358 + catch (Exception) 359 +#endif 360 + { 361 +#if !NET_COMPACT_20 && TRACE_PRELOAD 362 + try 363 + { 364 + Trace.WriteLine(String.Format( 365 + CultureInfo.CurrentCulture, 366 + "Native library pre-loader failed to get variable " + 367 + "\"{0}\" value: {1}", name, e)); /* throw */ 368 + } 369 + catch 370 + { 371 + // do nothing. 372 + } 373 +#endif 374 + } 375 + 376 + return value; 377 + } 378 + 379 + ///////////////////////////////////////////////////////////////////////// 380 + /// <summary> 381 + /// Queries and returns the directory for the assembly currently being 382 + /// executed. 383 + /// </summary> 384 + /// <returns> 385 + /// The directory for the assembly currently being executed -OR- null if 386 + /// it cannot be determined. 387 + /// </returns> 388 + private static string GetAssemblyDirectory() 389 + { 390 + try 391 + { 392 + Assembly assembly = Assembly.GetExecutingAssembly(); 393 + 394 + if (assembly == null) 395 + return null; 396 + 397 + string fileName; 398 + 399 +#if PLATFORM_COMPACTFRAMEWORK 400 + AssemblyName assemblyName = assembly.GetName(); 401 + 402 + if (assemblyName == null) 403 + return null; 404 + 405 + fileName = assemblyName.CodeBase; 406 +#else 407 + fileName = assembly.Location; 408 +#endif 409 + 410 + if (String.IsNullOrEmpty(fileName)) 411 + return null; 412 + 413 + string directory = Path.GetDirectoryName(fileName); 414 + 415 + if (String.IsNullOrEmpty(directory)) 416 + return null; 417 + 418 + return directory; 419 + } 420 +#if !NET_COMPACT_20 && TRACE_PRELOAD 421 + catch (Exception e) 422 +#else 423 + catch (Exception) 424 +#endif 425 + { 426 +#if !NET_COMPACT_20 && TRACE_PRELOAD 427 + try 428 + { 429 + Trace.WriteLine(String.Format( 430 + CultureInfo.CurrentCulture, 431 + "Native library pre-loader failed to get directory " + 432 + "for currently executing assembly: {0}", e)); /* throw */ 433 + } 434 + catch 435 + { 436 + // do nothing. 437 + } 438 +#endif 439 + } 440 + 441 + return null; 442 + } 443 + 444 + ///////////////////////////////////////////////////////////////////////// 445 + /// <summary> 251 446 /// Queries and returns the base directory of the current application 252 447 /// domain. 253 448 /// </summary> 254 449 /// <returns> 255 450 /// The base directory for the current application domain -OR- null if it 256 451 /// cannot be determined. 257 452 /// </returns> 258 453 private static string GetBaseDirectory() 259 454 { 260 -#if !PLATFORM_COMPACTFRAMEWORK 261 455 // 262 456 // NOTE: If the "PreLoadSQLite_BaseDirectory" environment variable 263 457 // is set, use it verbatim for the base directory. 264 458 // 265 - string directory = Environment.GetEnvironmentVariable( 266 - "PreLoadSQLite_BaseDirectory"); 459 + string directory = GetVariableValue("PreLoadSQLite_BaseDirectory"); 267 460 268 461 if (directory != null) 269 462 return directory; 270 463 464 +#if !PLATFORM_COMPACTFRAMEWORK 271 465 // 272 466 // NOTE: If the "PreLoadSQLite_UseAssemblyDirectory" environment 273 467 // variable is set (to anything), attempt to use the directory 274 468 // containing the currently executing assembly (i.e. 275 469 // System.Data.SQLite) intsead of the application domain base 276 470 // directory. 277 471 // 278 - if (Environment.GetEnvironmentVariable( 279 - "PreLoadSQLite_UseAssemblyDirectory") != null) 472 + if (GetVariableValue("PreLoadSQLite_UseAssemblyDirectory") != null) 280 473 { 281 - try 282 - { 283 - Assembly assembly = Assembly.GetExecutingAssembly(); 474 + directory = GetAssemblyDirectory(); 284 475 285 - if (assembly != null) 286 - { 287 - directory = Path.GetDirectoryName(assembly.Location); 288 - 289 - if (!String.IsNullOrEmpty(directory)) 290 - return directory; 291 - } 292 - } 293 - catch 294 - { 295 - // do nothing. 296 - } 476 + if (directory != null) 477 + return directory; 297 478 } 298 479 299 480 // 300 481 // NOTE: Otherwise, fallback on using the base directory of the 301 482 // current application domain. 302 483 // 303 484 return AppDomain.CurrentDomain.BaseDirectory; 304 485 #else 305 - Assembly assembly = Assembly.GetExecutingAssembly(); 306 - 307 - if (assembly == null) 308 - return null; 309 - 310 - AssemblyName assemblyName = assembly.GetName(); 311 - 312 - if (assemblyName == null) 313 - return null; 314 - 315 - try 316 - { 317 - return Path.GetDirectoryName(assemblyName.CodeBase); 318 - } 319 - catch 320 - { 321 - // do nothing. 322 - } 323 - 324 - return null; 486 + // 487 + // NOTE: Otherwise, fallback on using the directory containing 488 + // the currently executing assembly. 489 + // 490 + return GetAssemblyDirectory(); 325 491 #endif 326 492 } 327 493 328 494 ///////////////////////////////////////////////////////////////////////// 329 495 /// <summary> 330 496 /// Determines if the dynamic link library file name requires a suffix 331 497 /// and adds it if necessary. ................................................................................ 368 534 /// </summary> 369 535 /// <returns> 370 536 /// The processor architecture of the current process -OR- null if it 371 537 /// cannot be determined. 372 538 /// </returns> 373 539 private static string GetProcessorArchitecture() 374 540 { 375 -#if !PLATFORM_COMPACTFRAMEWORK 376 541 // 377 542 // NOTE: If the "PreLoadSQLite_ProcessorArchitecture" environment 378 543 // variable is set, use it verbatim for the current processor 379 544 // architecture. 380 545 // 381 - string processorArchitecture = Environment.GetEnvironmentVariable( 546 + string processorArchitecture = GetVariableValue( 382 547 "PreLoadSQLite_ProcessorArchitecture"); 383 548 384 549 if (processorArchitecture != null) 385 550 return processorArchitecture; 386 551 387 552 // 388 553 // BUGBUG: Will this always be reliable? 389 554 // 390 - processorArchitecture = Environment.GetEnvironmentVariable( 391 - PROCESSOR_ARCHITECTURE); 555 + processorArchitecture = GetVariableValue(PROCESSOR_ARCHITECTURE); 392 556 557 + ///////////////////////////////////////////////////////////////////// 558 + 559 +#if !PLATFORM_COMPACTFRAMEWORK 393 560 // 394 561 // HACK: Check for an "impossible" situation. If the pointer size 395 562 // is 32-bits, the processor architecture cannot be "AMD64". 396 563 // In that case, we are almost certainly hitting a bug in the 397 564 // operating system and/or Visual Studio that causes the 398 565 // PROCESSOR_ARCHITECTURE environment variable to contain the 399 566 // wrong value in some circumstances. Please refer to ticket ................................................................................ 415 582 // NOTE: We know that operating systems that return "AMD64" as 416 583 // the processor architecture are actually a superset of 417 584 // the "x86" processor architecture; therefore, return 418 585 // "x86" when the pointer size is 32-bits. 419 586 // 420 587 processorArchitecture = "x86"; 421 588 422 - // 423 - // NOTE: Show that we hit a fairly unusual situation (i.e. the 424 - // "wrong" processor architecture was detected). 425 - // 426 589 #if !NET_COMPACT_20 && TRACE_PRELOAD 427 - Trace.WriteLine(String.Format( 428 - CultureInfo.CurrentCulture, 429 - "Detected {0}-bit pointer size with processor architecture " + 430 - "\"{1}\", using processor architecture \"{2}\" instead...", 431 - IntPtr.Size * 8 /* bits */, savedProcessorArchitecture, 432 - processorArchitecture)); 590 + try 591 + { 592 + // 593 + // NOTE: Show that we hit a fairly unusual situation (i.e. the 594 + // "wrong" processor architecture was detected). 595 + // 596 + Trace.WriteLine(String.Format( 597 + CultureInfo.CurrentCulture, 598 + "Native library pre-loader detected {0}-bit pointer " + 599 + "size with processor architecture \"{1}\", using " + 600 + "processor architecture \"{2}\" instead...", 601 + IntPtr.Size * 8 /* bits */, savedProcessorArchitecture, 602 + processorArchitecture)); /* throw */ 603 + } 604 + catch 605 + { 606 + // do nothing. 607 + } 433 608 #endif 434 609 } 610 +#endif 435 611 436 - return processorArchitecture; 437 -#else 612 + ///////////////////////////////////////////////////////////////////// 613 + 614 +#if PLATFORM_COMPACTFRAMEWORK 438 615 // 439 616 // NOTE: On the .NET Compact Framework, attempt to use the native 440 617 // Win32 API function (via P/Invoke) that can provide us with 441 618 // the processor architecture. 442 619 // 443 620 try 444 621 { ................................................................................ 454 631 // the structure. 455 632 // 456 633 GetSystemInfo(out systemInfo); 457 634 458 635 // 459 636 // NOTE: Return the processor architecture value as a string. 460 637 // 461 - return systemInfo.wProcessorArchitecture.ToString(); 638 + processorArchitecture = 639 + systemInfo.wProcessorArchitecture.ToString(); 462 640 } 463 641 catch 464 642 { 465 643 // do nothing. 466 644 } 467 645 468 646 // 469 647 // NOTE: Upon failure, return an empty string. 470 648 // 471 - return String.Empty; 649 + processorArchitecture = String.Empty; 472 650 #endif 651 + 652 + return processorArchitecture; 473 653 } 474 654 475 655 ///////////////////////////////////////////////////////////////////////// 476 656 /// <summary> 477 657 /// Given the processor architecture, returns the name of the platform. 478 658 /// </summary> 479 659 /// <param name="processorArchitecture"> ................................................................................ 528 708 /// </returns> 529 709 private static IntPtr PreLoadSQLiteDll( 530 710 string directory, 531 711 string processorArchitecture 532 712 ) 533 713 { 534 714 // 535 - // NOTE: If the specified base directory is null, use the default. 715 + // NOTE: If the specified base directory is null, use the default 716 + // (i.e. attempt to automatically detect it). 536 717 // 537 718 if (directory == null) 538 719 directory = GetBaseDirectory(); 539 720 540 721 // 541 722 // NOTE: If we failed to query the base directory, stop now. 542 723 // ................................................................................ 603 784 // 604 785 if (!File.Exists(fileName)) 605 786 return IntPtr.Zero; 606 787 } 607 788 608 789 try 609 790 { 610 - // 611 - // NOTE: Show exactly where we are trying to load the native 612 - // SQLite library from. 613 - // 614 791 #if !NET_COMPACT_20 && TRACE_PRELOAD 615 - Trace.WriteLine(String.Format( 616 - CultureInfo.CurrentCulture, 617 - "Trying to load native SQLite library \"{0}\"...", 618 - fileName)); 792 + try 793 + { 794 + // 795 + // NOTE: Show exactly where we are trying to load the native 796 + // SQLite library from. 797 + // 798 + Trace.WriteLine(String.Format( 799 + CultureInfo.CurrentCulture, 800 + "Native library pre-loader is trying to load native " + 801 + "SQLite library \"{0}\"...", fileName)); /* throw */ 802 + } 803 + catch 804 + { 805 + // do nothing. 806 + } 619 807 #endif 620 808 621 809 // 622 810 // NOTE: Attempt to load the native library. This will either 623 811 // return a valid native module handle, return IntPtr.Zero, 624 812 // or throw an exception. 625 813 // ................................................................................ 633 821 { 634 822 #if !NET_COMPACT_20 && TRACE_PRELOAD 635 823 try 636 824 { 637 825 // 638 826 // NOTE: First, grab the last Win32 error number. 639 827 // 640 - int lastError = Marshal.GetLastWin32Error(); 828 + int lastError = Marshal.GetLastWin32Error(); /* throw */ 641 829 642 830 // 643 831 // NOTE: Show where we failed to load the native SQLite 644 832 // library from along with the Win32 error code and 645 833 // exception information. 646 834 // 647 835 Trace.WriteLine(String.Format( 648 836 CultureInfo.CurrentCulture, 649 - "Failed to load native SQLite library \"{0}\" " + 650 - "(getLastError = {1}): {2}", 837 + "Native library pre-loader failed to load native " + 838 + "SQLite library \"{0}\" (getLastError = {1}): {2}", 651 839 fileName, lastError, e)); /* throw */ 652 840 } 653 841 catch 654 842 { 655 843 // do nothing. 656 844 } 657 845 #endif ................................................................................ 2325 2513 SQLiteBase.CloseConnection(this, localHandle); 2326 2514 #endif 2327 2515 2328 2516 #if !NET_COMPACT_20 && TRACE_HANDLE 2329 2517 try 2330 2518 { 2331 2519 Trace.WriteLine(String.Format( 2332 - "CloseConnection: {0}", localHandle)); 2520 + "CloseConnection: {0}", localHandle)); /* throw */ 2333 2521 } 2334 2522 catch 2335 2523 { 2336 2524 } 2337 2525 #endif 2338 2526 #else 2339 2527 lock (syncRoot) ................................................................................ 2360 2548 #endif 2361 2549 { 2362 2550 #if !NET_COMPACT_20 && TRACE_HANDLE 2363 2551 try 2364 2552 { 2365 2553 Trace.WriteLine(String.Format( 2366 2554 "CloseConnection: {0}, exception: {1}", 2367 - handle, e)); 2555 + handle, e)); /* throw */ 2368 2556 } 2369 2557 catch 2370 2558 { 2371 2559 } 2372 2560 #endif 2373 2561 } 2374 2562 finally ................................................................................ 2511 2699 if (localHandle != IntPtr.Zero) 2512 2700 SQLiteBase.FinalizeStatement(cnn, localHandle); 2513 2701 2514 2702 #if !NET_COMPACT_20 && TRACE_HANDLE 2515 2703 try 2516 2704 { 2517 2705 Trace.WriteLine(String.Format( 2518 - "FinalizeStatement: {0}", localHandle)); 2706 + "FinalizeStatement: {0}", localHandle)); /* throw */ 2519 2707 } 2520 2708 catch 2521 2709 { 2522 2710 } 2523 2711 #endif 2524 2712 #else 2525 2713 lock (syncRoot) ................................................................................ 2546 2734 #endif 2547 2735 { 2548 2736 #if !NET_COMPACT_20 && TRACE_HANDLE 2549 2737 try 2550 2738 { 2551 2739 Trace.WriteLine(String.Format( 2552 2740 "FinalizeStatement: {0}, exception: {1}", 2553 - handle, e)); 2741 + handle, e)); /* throw */ 2554 2742 } 2555 2743 catch 2556 2744 { 2557 2745 } 2558 2746 #endif 2559 2747 } 2560 2748 finally ................................................................................ 2682 2870 if (localHandle != IntPtr.Zero) 2683 2871 SQLiteBase.FinishBackup(cnn, localHandle); 2684 2872 2685 2873 #if !NET_COMPACT_20 && TRACE_HANDLE 2686 2874 try 2687 2875 { 2688 2876 Trace.WriteLine(String.Format( 2689 - "FinishBackup: {0}", localHandle)); 2877 + "FinishBackup: {0}", localHandle)); /* throw */ 2690 2878 } 2691 2879 catch 2692 2880 { 2693 2881 } 2694 2882 #endif 2695 2883 #else 2696 2884 lock (syncRoot) ................................................................................ 2717 2905 #endif 2718 2906 { 2719 2907 #if !NET_COMPACT_20 && TRACE_HANDLE 2720 2908 try 2721 2909 { 2722 2910 Trace.WriteLine(String.Format( 2723 2911 "FinishBackup: {0}, exception: {1}", 2724 - handle, e)); 2912 + handle, e)); /* throw */ 2725 2913 } 2726 2914 catch 2727 2915 { 2728 2916 } 2729 2917 #endif 2730 2918 } 2731 2919 finally