-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
Copy pathInterop.cs
198 lines (167 loc) · 7.89 KB
/
Interop.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Reflection;
namespace Microsoft.DotNet.NativeWrapper
{
public static partial class Interop
{
public static readonly bool RunningOnWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
#if NETCOREAPP
private static readonly string? HostFxrPath;
#endif
static Interop()
{
if (RunningOnWindows)
{
PreloadWindowsLibrary(Constants.HostFxr);
}
#if NETCOREAPP
else
{
HostFxrPath = (string)AppContext.GetData(Constants.RuntimeProperty.HostFxrPath)!;
System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly())!.ResolvingUnmanagedDll += HostFxrResolver;
}
#endif
}
// MSBuild SDK resolvers are required to be AnyCPU, but we have a native dependency and .NETFramework does not
// have a built-in facility for dynamically loading user native dlls for the appropriate platform. We therefore
// preload the version with the correct architecture (from a corresponding sub-folder relative to us) on static
// construction so that subsequent P/Invokes can find it.
private static void PreloadWindowsLibrary(string dllFileName)
{
string? basePath = Path.GetDirectoryName(typeof(Interop).Assembly.Location);
string architecture = RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant();
string dllPath = Path.Combine(basePath ?? string.Empty, architecture, $"{dllFileName}.dll");
// return value is intentionally ignored as we let the subsequent P/Invokes fail naturally.
LoadLibraryExW(dllPath, IntPtr.Zero, LOAD_WITH_ALTERED_SEARCH_PATH);
}
#if NETCOREAPP
private static IntPtr HostFxrResolver(Assembly assembly, string libraryName)
{
if (libraryName != Constants.HostFxr)
{
return IntPtr.Zero;
}
if (string.IsNullOrEmpty(HostFxrPath))
{
throw new HostFxrRuntimePropertyNotSetException();
}
if (!NativeLibrary.TryLoad(HostFxrPath, out var handle))
{
throw new HostFxrNotFoundException(HostFxrPath);
}
return handle;
}
#endif
// lpFileName passed to LoadLibraryEx must be a full path.
private const int LOAD_WITH_ALTERED_SEARCH_PATH = 0x8;
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr LoadLibraryExW(string lpFileName, IntPtr hFile, int dwFlags);
[Flags]
internal enum hostfxr_resolve_sdk2_flags_t : int
{
disallow_prerelease = 0x1,
}
internal enum hostfxr_resolve_sdk2_result_key_t : int
{
resolved_sdk_dir = 0,
global_json_path = 1,
requested_version = 2,
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct hostfxr_dotnet_environment_info
{
public nuint size;
public string hostfxr_version;
public string hostfxr_commit_hash;
public nuint sdk_count;
public IntPtr sdks;
public nuint framework_count;
public IntPtr frameworks;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct hostfxr_dotnet_environment_framework_info
{
public nuint size;
public string name;
public string version;
public string path;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct hostfxr_dotnet_environment_sdk_info
{
public nuint size;
public string version;
public string path;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Auto)]
internal delegate void hostfxr_get_dotnet_environment_info_result_fn(
IntPtr info,
IntPtr result_context);
[DllImport(Constants.HostFxr, CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
internal static extern int hostfxr_get_dotnet_environment_info(
string dotnet_root,
IntPtr reserved,
hostfxr_get_dotnet_environment_info_result_fn result,
IntPtr result_context);
public static class Windows
{
private const CharSet UTF16 = CharSet.Unicode;
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = UTF16)]
internal delegate void hostfxr_resolve_sdk2_result_fn(
hostfxr_resolve_sdk2_result_key_t key,
string value);
[DllImport(Constants.HostFxr, CharSet = UTF16, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
internal static extern int hostfxr_resolve_sdk2(
string? exe_dir,
string? working_dir,
hostfxr_resolve_sdk2_flags_t flags,
hostfxr_resolve_sdk2_result_fn result);
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = UTF16)]
internal delegate void hostfxr_get_available_sdks_result_fn(
int sdk_count,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
string[] sdk_dirs);
[DllImport(Constants.HostFxr, CharSet = UTF16, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
internal static extern int hostfxr_get_available_sdks(
string? exe_dir,
hostfxr_get_available_sdks_result_fn result);
}
public static class Unix
{
// Ansi marshaling on Unix is actually UTF8
private const CharSet UTF8 = CharSet.Ansi;
private static string? PtrToStringUTF8(IntPtr ptr) => Marshal.PtrToStringAnsi(ptr);
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = UTF8)]
internal delegate void hostfxr_resolve_sdk2_result_fn(
hostfxr_resolve_sdk2_result_key_t key,
string value);
[DllImport(Constants.HostFxr, CharSet = UTF8, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
internal static extern int hostfxr_resolve_sdk2(
string? exe_dir,
string? working_dir,
hostfxr_resolve_sdk2_flags_t flags,
hostfxr_resolve_sdk2_result_fn result);
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = UTF8)]
internal delegate void hostfxr_get_available_sdks_result_fn(
int sdk_count,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)]
string[] sdk_dirs);
[DllImport(Constants.HostFxr, CharSet = UTF8, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
internal static extern int hostfxr_get_available_sdks(
string? exe_dir,
hostfxr_get_available_sdks_result_fn result);
[DllImport("libc", CharSet = UTF8, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr realpath(string path, IntPtr buffer);
[DllImport("libc", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
private static extern void free(IntPtr ptr);
public static string? realpath(string path)
{
var ptr = realpath(path, IntPtr.Zero);
var result = PtrToStringUTF8(ptr);
free(ptr);
return result;
}
}
}
}