Win32Marshal.cs 4.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Runtime.InteropServices;
  5. namespace System.IO
  6. {
  7. /// <summary>
  8. /// Provides static methods for converting from Win32 errors codes to exceptions, HRESULTS and error messages.
  9. /// </summary>
  10. internal static class Win32Marshal
  11. {
  12. /// <summary>
  13. /// Converts, resetting it, the last Win32 error into a corresponding <see cref="Exception"/> object, optionally
  14. /// including the specified path in the error message.
  15. /// </summary>
  16. internal static Exception GetExceptionForLastWin32Error(string path = "")
  17. => GetExceptionForWin32Error(Marshal.GetLastWin32Error(), path);
  18. /// <summary>
  19. /// Converts the specified Win32 error into a corresponding <see cref="Exception"/> object, optionally
  20. /// including the specified path in the error message.
  21. /// </summary>
  22. internal static Exception GetExceptionForWin32Error(int errorCode, string path = "")
  23. {
  24. switch (errorCode)
  25. {
  26. case Interop.Errors.ERROR_FILE_NOT_FOUND:
  27. return new FileNotFoundException(
  28. string.IsNullOrEmpty(path) ? SR.IO_FileNotFound : SR.Format(SR.IO_FileNotFound_FileName, path), path);
  29. case Interop.Errors.ERROR_PATH_NOT_FOUND:
  30. return new DirectoryNotFoundException(
  31. string.IsNullOrEmpty(path) ? SR.IO_PathNotFound_NoPathName : SR.Format(SR.IO_PathNotFound_Path, path));
  32. case Interop.Errors.ERROR_ACCESS_DENIED:
  33. return new UnauthorizedAccessException(
  34. string.IsNullOrEmpty(path) ? SR.UnauthorizedAccess_IODenied_NoPathName : SR.Format(SR.UnauthorizedAccess_IODenied_Path, path));
  35. case Interop.Errors.ERROR_ALREADY_EXISTS:
  36. if (string.IsNullOrEmpty(path))
  37. goto default;
  38. return new IOException(SR.Format(SR.IO_AlreadyExists_Name, path), MakeHRFromErrorCode(errorCode));
  39. case Interop.Errors.ERROR_FILENAME_EXCED_RANGE:
  40. return new PathTooLongException(
  41. string.IsNullOrEmpty(path) ? SR.IO_PathTooLong : SR.Format(SR.IO_PathTooLong_Path, path));
  42. case Interop.Errors.ERROR_SHARING_VIOLATION:
  43. return new IOException(
  44. string.IsNullOrEmpty(path) ? SR.IO_SharingViolation_NoFileName : SR.Format(SR.IO_SharingViolation_File, path),
  45. MakeHRFromErrorCode(errorCode));
  46. case Interop.Errors.ERROR_FILE_EXISTS:
  47. if (string.IsNullOrEmpty(path))
  48. goto default;
  49. return new IOException(SR.Format(SR.IO_FileExists_Name, path), MakeHRFromErrorCode(errorCode));
  50. case Interop.Errors.ERROR_OPERATION_ABORTED:
  51. return new OperationCanceledException();
  52. case Interop.Errors.ERROR_INVALID_PARAMETER:
  53. default:
  54. return new IOException(
  55. string.IsNullOrEmpty(path) ? GetMessage(errorCode) : $"{GetMessage(errorCode)} : '{path}'",
  56. MakeHRFromErrorCode(errorCode));
  57. }
  58. }
  59. /// <summary>
  60. /// If not already an HRESULT, returns an HRESULT for the specified Win32 error code.
  61. /// </summary>
  62. internal static int MakeHRFromErrorCode(int errorCode)
  63. {
  64. // Don't convert it if it is already an HRESULT
  65. if ((0xFFFF0000 & errorCode) != 0)
  66. return errorCode;
  67. return unchecked(((int)0x80070000) | errorCode);
  68. }
  69. /// <summary>
  70. /// Returns a Win32 error code for the specified HRESULT if it came from FACILITY_WIN32
  71. /// If not, returns the HRESULT unchanged
  72. /// </summary>
  73. internal static int TryMakeWin32ErrorCodeFromHR(int hr)
  74. {
  75. if ((0xFFFF0000 & hr) == 0x80070000)
  76. {
  77. // Win32 error, Win32Marshal.GetExceptionForWin32Error expects the Win32 format
  78. hr &= 0x0000FFFF;
  79. }
  80. return hr;
  81. }
  82. /// <summary>
  83. /// Returns a string message for the specified Win32 error code.
  84. /// </summary>
  85. internal static string GetMessage(int errorCode) => Interop.Kernel32.GetMessage(errorCode);
  86. }
  87. }