SkNativeDependencyCompatibilityChecker.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. using System;
  2. using System.Linq;
  3. using System.Runtime.InteropServices;
  4. namespace QuestPDF.Skia;
  5. internal static class SkNativeDependencyCompatibilityChecker
  6. {
  7. private static bool IsCompatibilityChecked = false;
  8. public static void Test()
  9. {
  10. const string exceptionBaseMessage = "The QuestPDF library has encountered an issue while loading one of its dependencies.";
  11. const string paragraph = "\n\n";
  12. if (IsCompatibilityChecked)
  13. return;
  14. // test with dotnet-based mechanism where native files are provided
  15. // in the "runtimes/{rid}/native" folder on Core, or by the targets file on .NET Framework
  16. var innerException = CheckIfExceptionIsThrownWhenLoadingNativeDependencies();
  17. if (innerException == null)
  18. {
  19. IsCompatibilityChecked = true;
  20. return;
  21. }
  22. if (!SkNativeDependencyProvider.IsCurrentPlatformSupported())
  23. ThrowCompatibilityException(innerException);
  24. // detect platform, copy appropriate native files and test compatibility again
  25. SkNativeDependencyProvider.EnsureNativeFileAvailability();
  26. innerException = CheckIfExceptionIsThrownWhenLoadingNativeDependencies();
  27. if (innerException == null)
  28. {
  29. IsCompatibilityChecked = true;
  30. return;
  31. }
  32. ThrowCompatibilityException(innerException);
  33. static void ThrowCompatibilityException(Exception innerException)
  34. {
  35. var supportedRuntimes = string.Join(", ", SkNativeDependencyProvider.SupportedPlatforms);
  36. var currentRuntime = SkNativeDependencyProvider.GetRuntimePlatform();
  37. var message =
  38. $"{exceptionBaseMessage}{paragraph}" +
  39. "Your runtime is currently not supported by QuestPDF. " +
  40. $"Currently supported runtimes are: {supportedRuntimes}. ";
  41. if (SkNativeDependencyProvider.SupportedPlatforms.Contains(currentRuntime))
  42. {
  43. message += $"{paragraph}It appears that your current operating system distribution may be outdated. For optimal compatibility, please consider updating it to a more recent version.";
  44. }
  45. else
  46. {
  47. message += $"{paragraph}Your current runtime is detected as '{currentRuntime}'.";
  48. }
  49. if (RuntimeInformation.ProcessArchitecture is Architecture.Arm)
  50. message += $"{paragraph}Please consider setting the 'Platform target' property to 'Arm64' in your project settings.";
  51. throw new Exception(message, innerException);
  52. }
  53. }
  54. private static Exception? CheckIfExceptionIsThrownWhenLoadingNativeDependencies()
  55. {
  56. try
  57. {
  58. var random = new Random();
  59. var a = random.Next();
  60. var b = random.Next();
  61. var expected = a + b;
  62. var returned = API.check_compatibility_by_calculating_sum(a, b);
  63. if (expected != returned)
  64. throw new Exception();
  65. return null;
  66. }
  67. catch (Exception exception)
  68. {
  69. return exception;
  70. }
  71. }
  72. private static class API
  73. {
  74. [DllImport(SkiaAPI.LibraryName, CallingConvention = CallingConvention.Cdecl)]
  75. public static extern int check_compatibility_by_calculating_sum(int a, int b);
  76. }
  77. }