Skip to content

Commit ac1b991

Browse files
author
Josh Peterson
committed
Work around UWP Windows SDK limitations
Four functions used via p/invoke in the class library code for Windows are not present in Windows SDK versions before 16299: * SetThreadErrorMode * CopyFileExW * DeleteVolumeMountPointW * GetLogicalDrives In IL2CPP on UWP with older Windows SDK versions, calls to these functions will cause a `DllNotFoundException` to occur. Work around these exceptions with alternative implementations or useful error messages.
1 parent da177d5 commit ac1b991

File tree

7 files changed

+253
-5
lines changed

7 files changed

+253
-5
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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+
5+
using System;
6+
using System.IO;
7+
using System.Runtime.InteropServices;
8+
9+
internal partial class Interop
10+
{
11+
internal partial class Kernel32
12+
{
13+
// Rename this method so that it does not conflict with the method of the
14+
// same name for Windows Desktop. In the unityjit profile, this source
15+
// file is not included in the build.
16+
#if UNITY_AOT && WIN_PLATFORM
17+
internal static int CopyFileUWP(string src, string dst, bool failIfExists)
18+
#else
19+
internal static int CopyFile(string src, string dst, bool failIfExists)
20+
#endif
21+
{
22+
uint copyFlags = failIfExists ? (uint)Interop.Kernel32.FileOperations.COPY_FILE_FAIL_IF_EXISTS : 0;
23+
Interop.Kernel32.COPYFILE2_EXTENDED_PARAMETERS parameters = new Interop.Kernel32.COPYFILE2_EXTENDED_PARAMETERS()
24+
{
25+
dwSize = (uint)Marshal.SizeOf<Interop.Kernel32.COPYFILE2_EXTENDED_PARAMETERS>(),
26+
dwCopyFlags = copyFlags
27+
};
28+
29+
int hr = Interop.Kernel32.CopyFile2(src, dst, ref parameters);
30+
31+
return Win32Marshal.TryMakeWin32ErrorCodeFromHR(hr);
32+
}
33+
}
34+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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+
5+
using System;
6+
using System.Runtime.InteropServices;
7+
8+
internal partial class Interop
9+
{
10+
internal partial class Kernel32
11+
{
12+
#if UNITY_AOT && WIN_PLATFORM
13+
static bool useUWPFallback = false;
14+
#endif
15+
internal static int CopyFile(string src, string dst, bool failIfExists)
16+
{
17+
int copyFlags = failIfExists ? Interop.Kernel32.FileOperations.COPY_FILE_FAIL_IF_EXISTS : 0;
18+
int cancel = 0;
19+
// The CopyFileExW method does not exist on Windows SDK versions
20+
// before 16299. This is manifested at runtime in IL2CPP as a DllNotFoundException
21+
// for kernel32.dll. If this happens, fall back to a copy file implementation
22+
// that does work on UWP with that SDK.
23+
#if UNITY_AOT && WIN_PLATFORM
24+
if (useUWPFallback)
25+
return CopyFileUWP(src, dst, failIfExists);
26+
27+
try
28+
{
29+
#endif
30+
if (!Interop.Kernel32.CopyFileEx(src, dst, IntPtr.Zero, IntPtr.Zero, ref cancel, copyFlags))
31+
{
32+
return Marshal.GetLastWin32Error();
33+
}
34+
#if UNITY_AOT && WIN_PLATFORM
35+
}
36+
catch(DllNotFoundException)
37+
{
38+
useUWPFallback = true;
39+
return CopyFileUWP(src, dst, failIfExists);
40+
}
41+
#endif
42+
return Interop.Errors.ERROR_SUCCESS;
43+
}
44+
}
45+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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+
5+
using Microsoft.Win32.SafeHandles;
6+
using System.IO;
7+
using System.Runtime.InteropServices;
8+
9+
internal partial class Interop
10+
{
11+
internal partial class Kernel32
12+
{
13+
/// <summary>
14+
/// WARNING: This method does not implicitly handle long paths. Use DeleteVolumeMountPoint.
15+
/// </summary>
16+
[DllImport(Libraries.Kernel32, EntryPoint = "DeleteVolumeMountPointW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
17+
internal static extern bool DeleteVolumeMountPointPrivate(string mountPoint);
18+
19+
20+
internal static bool DeleteVolumeMountPoint(string mountPoint)
21+
{
22+
mountPoint = PathInternal.EnsureExtendedPrefixIfNeeded(mountPoint);
23+
// The DeleteVolumeMountPointW method does not exist on Windows SDK versions
24+
// before 16299. This is manifested at runtime in IL2CPP as a DllNotFoundException
25+
// for kernel32.dll. If this happens, throw a proper exception, as this should not
26+
// be possible for UWP apps.
27+
#if UNITY_AOT && WIN_PLATFORM
28+
try
29+
{
30+
#endif
31+
return DeleteVolumeMountPointPrivate(mountPoint);
32+
#if UNITY_AOT && WIN_PLATFORM
33+
}
34+
catch (System.DllNotFoundException)
35+
{
36+
throw new System.UnauthorizedAccessException();
37+
}
38+
#endif
39+
}
40+
}
41+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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+
5+
using System.Diagnostics;
6+
using System.Text;
7+
8+
namespace System.IO
9+
{
10+
/// <summary>Contains internal volume helpers that are shared between many projects.</summary>
11+
internal static partial class DriveInfoInternal
12+
{
13+
public static string[] GetLogicalDrives()
14+
{
15+
int drives = 0;
16+
// The GetLogicalDrives method does not exist on Windows SDK versions
17+
// before 16299. This is manifested at runtime in IL2CPP as a DllNotFoundException
18+
// for kernel32.dll. If this happens, throw an exception.
19+
#if UNITY_AOT && WIN_PLATFORM
20+
try
21+
{
22+
#endif
23+
drives = Interop.Kernel32.GetLogicalDrives();
24+
#if UNITY_AOT && WIN_PLATFORM
25+
}
26+
catch (System.DllNotFoundException)
27+
{
28+
throw new InvalidOperationException("GetLogicalDrives is not supported using this version of the Windows SDK. Use SDK versions greater than 16299.");
29+
}
30+
#endif
31+
if (drives == 0)
32+
throw Win32Marshal.GetExceptionForLastWin32Error();
33+
34+
// GetLogicalDrives returns a bitmask starting from
35+
// position 0 "A" indicating whether a drive is present.
36+
// Loop over each bit, creating a string for each one
37+
// that is set.
38+
39+
uint d = (uint)drives;
40+
int count = 0;
41+
while (d != 0)
42+
{
43+
if (((int)d & 1) != 0) count++;
44+
d >>= 1;
45+
}
46+
47+
string[] result = new string[count];
48+
char[] root = new char[] { 'A', ':', '\\' };
49+
d = (uint)drives;
50+
count = 0;
51+
while (d != 0)
52+
{
53+
if (((int)d & 1) != 0)
54+
{
55+
result[count++] = new string(root);
56+
}
57+
d >>= 1;
58+
root[0]++;
59+
}
60+
return result;
61+
}
62+
}
63+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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+
5+
namespace System.IO
6+
{
7+
/// <summary>
8+
/// Simple wrapper to safely disable the normal media insertion prompt for
9+
/// removable media (floppies, cds, memory cards, etc.)
10+
/// </summary>
11+
/// <remarks>
12+
/// Note that removable media file systems lazily load. After starting the OS
13+
/// they won't be loaded until you have media in the drive- and as such the
14+
/// prompt won't happen. You have to have had media in at least once to get
15+
/// the file system to load and then have removed it.
16+
/// </remarks>
17+
internal struct DisableMediaInsertionPrompt : IDisposable
18+
{
19+
private bool _disableSuccess;
20+
private uint _oldMode;
21+
22+
#if UNITY_AOT && WIN_PLATFORM
23+
static bool useUWPFallback = false;
24+
#endif
25+
26+
public static DisableMediaInsertionPrompt Create()
27+
{
28+
DisableMediaInsertionPrompt prompt = new DisableMediaInsertionPrompt();
29+
// The SetThreadErrorMode method does not exist on Windows SDK versions
30+
// before 16299. This is manifested at runtime in IL2CPP as a DllNotFoundException
31+
// for kernel32.dll. If this happens, assume that there is no media insertion
32+
// prompt and continue.
33+
#if UNITY_AOT && WIN_PLATFORM
34+
if (useUWPFallback)
35+
{
36+
prompt._disableSuccess = false;
37+
return prompt;
38+
}
39+
40+
try
41+
{
42+
#endif
43+
prompt._disableSuccess = Interop.Kernel32.SetThreadErrorMode(Interop.Kernel32.SEM_FAILCRITICALERRORS, out prompt._oldMode);
44+
#if UNITY_AOT && WIN_PLATFORM
45+
}
46+
catch (DllNotFoundException)
47+
{
48+
useUWPFallback = true;
49+
prompt._disableSuccess = false;
50+
}
51+
#endif
52+
return prompt;
53+
}
54+
55+
public void Dispose()
56+
{
57+
uint ignore;
58+
if (_disableSuccess)
59+
Interop.Kernel32.SetThreadErrorMode(_oldMode, out ignore);
60+
}
61+
}
62+
}

mcs/class/corlib/win32_build_corlib.dll.sources

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.FILE_TIME.cs
1818
../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.FileAttributes.cs
1919
../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.CreateFile.cs
20-
../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.CopyFile.cs
20+
../../../external/corefx-bugfix/src/Common/src/Interop/Windows/kernel32/Interop.CopyFile.cs
2121
../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.CopyFileEx.cs
2222
../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.DeleteFile.cs
2323
../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.GetFileAttributesEx.cs
@@ -36,7 +36,7 @@
3636
../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.FILE_INFO_BY_HANDLE_CLASS.cs
3737
../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.CloseHandle.cs
3838
../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.SetFileInformationByHandle.cs
39-
../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.DeleteVolumeMountPoint.cs
39+
../../../external/corefx-bugfix/src/Common/src/Interop/Windows/kernel32/Interop.DeleteVolumeMountPoint.cs
4040
../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.SetThreadErrorMode.cs
4141
../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.GetLogicalDrive.cs
4242
../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.FormatMessage.cs
@@ -57,13 +57,13 @@
5757
../../../external/corefx/src/Common/src/CoreLib/System/IO/Win32Marshal.cs
5858
../../../external/corefx/src/Common/src/CoreLib/System/IO/PathInternal.Windows.cs
5959
../../../external/corefx/src/Common/src/CoreLib/Internal/IO/File.Windows.cs
60-
../../../external/corefx/src/Common/src/System/IO/DriveInfoInternal.Win32.cs
60+
../../../external/corefx-bugfix/src/Common/src/System/IO/DriveInfoInternal.Win32.cs
6161
../../../external/corefx/src/System.IO.FileSystem/src/System/IO/FileSystem.Windows.cs
6262
../../../external/corefx/src/System.IO.FileSystem/src/System/IO/FileSystemInfo.Windows.cs
6363
../../../external/corefx/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Windows.cs
6464
../../../external/corefx/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.Win32.cs
6565
../../../external/corefx/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEntry.Windows.cs
66-
../../../external/corefx/src/System.IO.FileSystem/src/System/IO/DisableMediaInsertionPrompt.cs
66+
../../../external/corefx-bugfix/src/System.IO.FileSystem/src/System/IO/DisableMediaInsertionPrompt.cs
6767

6868
../../../external/corefx/src/Common/src/System/Memory/FixedBufferExtensions.cs
6969

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
#include win32_net_4_x_corlib.dll.sources
22

33
../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.GetFileInformationByHandleEx.cs
4-
../../../external/corefx/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.WinRT.cs
4+
../../../external/corefx/src/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEnumerator.WinRT.cs
5+
../../../external/corefx-bugfix/src/Common/src/Interop/Windows/kernel32/Interop.CopyFile.Uap.cs
6+
../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.CopyFile2.cs
7+
../../../external/corefx/src/Common/src/Interop/Windows/kernel32/Interop.COPYFILE2_EXTENDED_PARAMETERS.cs

0 commit comments

Comments
 (0)