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.Text; 7 using System.Runtime.InteropServices; 8 using System.Diagnostics; 9 using Interlocked = System.Threading.Interlocked; 10 11 namespace Internal.Runtime.CompilerHelpers 12 { 13 /// <summary> 14 /// These methods are used to throw exceptions from generated code. 15 /// </summary> 16 internal static class InteropHelpers 17 { StringToAnsiString(String str, bool bestFit, bool throwOnUnmappableChar)18 internal static unsafe byte* StringToAnsiString(String str, bool bestFit, bool throwOnUnmappableChar) 19 { 20 return PInvokeMarshal.StringToAnsiString(str, bestFit, throwOnUnmappableChar); 21 } 22 AnsiStringToString(byte* buffer)23 public static unsafe string AnsiStringToString(byte* buffer) 24 { 25 return PInvokeMarshal.AnsiStringToString(buffer); 26 } 27 28 StringToByValAnsiString(string str, byte* pNative, int charCount, bool bestFit, bool throwOnUnmappableChar)29 internal static unsafe void StringToByValAnsiString(string str, byte* pNative, int charCount, bool bestFit, bool throwOnUnmappableChar) 30 { 31 // In CoreRT charCount = Min(SizeConst, str.Length). So we don't need to truncate again. 32 PInvokeMarshal.StringToByValAnsiString(str, pNative, charCount, bestFit, throwOnUnmappableChar, truncate: false); 33 } 34 ByValAnsiStringToString(byte* buffer, int length)35 public static unsafe string ByValAnsiStringToString(byte* buffer, int length) 36 { 37 return PInvokeMarshal.ByValAnsiStringToString(buffer, length); 38 } 39 StringToUnicodeFixedArray(String str, UInt16* buffer, int length)40 internal static unsafe void StringToUnicodeFixedArray(String str, UInt16* buffer, int length) 41 { 42 if (buffer == null) 43 return; 44 45 if (str == null) 46 { 47 buffer[0] = '\0'; 48 return; 49 } 50 51 Debug.Assert(str.Length >= length); 52 53 fixed (char* pStr = str) 54 { 55 int size = length * sizeof(char); 56 Buffer.MemoryCopy(pStr, buffer, size, size); 57 *(buffer + length) = 0; 58 } 59 } 60 UnicodeToStringFixedArray(UInt16* buffer, int length)61 internal static unsafe string UnicodeToStringFixedArray(UInt16* buffer, int length) 62 { 63 if (buffer == null) 64 return String.Empty; 65 66 string result = String.Empty; 67 68 if (length > 0) 69 { 70 result = new String(' ', length); 71 72 fixed (char* pTemp = result) 73 { 74 int size = length * sizeof(char); 75 Buffer.MemoryCopy(buffer, pTemp, size, size); 76 } 77 } 78 return result; 79 } 80 StringToUnicodeBuffer(String str)81 internal static unsafe char* StringToUnicodeBuffer(String str) 82 { 83 if (str == null) 84 return null; 85 86 int stringLength = str.Length; 87 88 char* buffer = (char*)PInvokeMarshal.CoTaskMemAlloc((UIntPtr)(sizeof(char) * (stringLength + 1))).ToPointer(); 89 90 fixed (char* pStr = str) 91 { 92 int size = stringLength * sizeof(char); 93 Buffer.MemoryCopy(pStr, buffer, size, size); 94 *(buffer + stringLength) = '\0'; 95 } 96 return buffer; 97 } 98 UnicodeBufferToString(char* buffer)99 public static unsafe string UnicodeBufferToString(char* buffer) 100 { 101 return new String(buffer); 102 } 103 AllocMemoryForAnsiStringBuilder(StringBuilder sb)104 public static unsafe byte* AllocMemoryForAnsiStringBuilder(StringBuilder sb) 105 { 106 if (sb == null) 107 { 108 return null; 109 } 110 return (byte *)CoTaskMemAllocAndZeroMemory(new IntPtr(checked((sb.Capacity + 2) * PInvokeMarshal.GetSystemMaxDBCSCharSize()))); 111 } 112 AllocMemoryForUnicodeStringBuilder(StringBuilder sb)113 public static unsafe char* AllocMemoryForUnicodeStringBuilder(StringBuilder sb) 114 { 115 if (sb == null) 116 { 117 return null; 118 } 119 return (char *)CoTaskMemAllocAndZeroMemory(new IntPtr(checked((sb.Capacity + 2) * 2))); 120 } 121 AllocMemoryForAnsiCharArray(char[] chArray)122 public static unsafe byte* AllocMemoryForAnsiCharArray(char[] chArray) 123 { 124 if (chArray == null) 125 { 126 return null; 127 } 128 return (byte*)CoTaskMemAllocAndZeroMemory(new IntPtr(checked((chArray.Length + 2) * PInvokeMarshal.GetSystemMaxDBCSCharSize()))); 129 } 130 AnsiStringToStringBuilder(byte* newBuffer, System.Text.StringBuilder stringBuilder)131 public static unsafe void AnsiStringToStringBuilder(byte* newBuffer, System.Text.StringBuilder stringBuilder) 132 { 133 if (stringBuilder == null) 134 return; 135 136 PInvokeMarshal.AnsiStringToStringBuilder(newBuffer, stringBuilder); 137 } 138 UnicodeStringToStringBuilder(ushort* newBuffer, System.Text.StringBuilder stringBuilder)139 public static unsafe void UnicodeStringToStringBuilder(ushort* newBuffer, System.Text.StringBuilder stringBuilder) 140 { 141 if (stringBuilder == null) 142 return; 143 144 PInvokeMarshal.UnicodeStringToStringBuilder(newBuffer, stringBuilder); 145 } 146 StringBuilderToAnsiString(System.Text.StringBuilder stringBuilder, byte* pNative, bool bestFit, bool throwOnUnmappableChar)147 public static unsafe void StringBuilderToAnsiString(System.Text.StringBuilder stringBuilder, byte* pNative, 148 bool bestFit, bool throwOnUnmappableChar) 149 { 150 if (pNative == null) 151 return; 152 153 PInvokeMarshal.StringBuilderToAnsiString(stringBuilder, pNative, bestFit, throwOnUnmappableChar); 154 } 155 StringBuilderToUnicodeString(System.Text.StringBuilder stringBuilder, ushort* destination)156 public static unsafe void StringBuilderToUnicodeString(System.Text.StringBuilder stringBuilder, ushort* destination) 157 { 158 if (destination == null) 159 return; 160 161 PInvokeMarshal.StringBuilderToUnicodeString(stringBuilder, destination); 162 } 163 WideCharArrayToAnsiCharArray(char[] managedArray, byte* pNative, bool bestFit, bool throwOnUnmappableChar)164 public static unsafe void WideCharArrayToAnsiCharArray(char[] managedArray, byte* pNative, bool bestFit, bool throwOnUnmappableChar) 165 { 166 PInvokeMarshal.WideCharArrayToAnsiCharArray(managedArray, pNative, bestFit, throwOnUnmappableChar); 167 } 168 169 /// <summary> 170 /// Convert ANSI ByVal byte array to UNICODE wide char array, best fit 171 /// </summary> 172 /// <remarks> 173 /// * This version works with array instead to string, it means that the len must be provided and there will be NO NULL to 174 /// terminate the array. 175 /// * The buffer to the UNICODE wide char array must be allocated by the caller. 176 /// </remarks> 177 /// <param name="pNative">Pointer to the ANSI byte array. Could NOT be null.</param> 178 /// <param name="lenInBytes">Maximum buffer size.</param> 179 /// <param name="managedArray">Wide char array that has already been allocated.</param> AnsiCharArrayToWideCharArray(byte* pNative, char[] managedArray)180 public static unsafe void AnsiCharArrayToWideCharArray(byte* pNative, char[] managedArray) 181 { 182 PInvokeMarshal.AnsiCharArrayToWideCharArray(pNative, managedArray); 183 } 184 185 /// <summary> 186 /// Convert a single UNICODE wide char to a single ANSI byte. 187 /// </summary> 188 /// <param name="managedArray">single UNICODE wide char value</param> WideCharToAnsiChar(char managedValue, bool bestFit, bool throwOnUnmappableChar)189 public static unsafe byte WideCharToAnsiChar(char managedValue, bool bestFit, bool throwOnUnmappableChar) 190 { 191 return PInvokeMarshal.WideCharToAnsiChar(managedValue, bestFit, throwOnUnmappableChar); 192 } 193 194 /// <summary> 195 /// Convert a single ANSI byte value to a single UNICODE wide char value, best fit. 196 /// </summary> 197 /// <param name="nativeValue">Single ANSI byte value.</param> AnsiCharToWideChar(byte nativeValue)198 public static unsafe char AnsiCharToWideChar(byte nativeValue) 199 { 200 return PInvokeMarshal.AnsiCharToWideChar(nativeValue); 201 } 202 ResolvePInvoke(MethodFixupCell* pCell)203 internal static unsafe IntPtr ResolvePInvoke(MethodFixupCell* pCell) 204 { 205 if (pCell->Target != IntPtr.Zero) 206 return pCell->Target; 207 208 return ResolvePInvokeSlow(pCell); 209 } 210 ResolvePInvokeSlow(MethodFixupCell* pCell)211 internal static unsafe IntPtr ResolvePInvokeSlow(MethodFixupCell* pCell) 212 { 213 ModuleFixupCell* pModuleCell = pCell->Module; 214 IntPtr hModule = pModuleCell->Handle; 215 if (hModule == IntPtr.Zero) 216 { 217 FixupModuleCell(pModuleCell); 218 hModule = pModuleCell->Handle; 219 } 220 221 FixupMethodCell(hModule, pCell); 222 return pCell->Target; 223 } 224 TryResolveModule(string moduleName)225 internal static unsafe IntPtr TryResolveModule(string moduleName) 226 { 227 IntPtr hModule = IntPtr.Zero; 228 229 // Try original name first 230 hModule = LoadLibrary(moduleName); 231 if (hModule != IntPtr.Zero) return hModule; 232 233 #if PLATFORM_UNIX 234 const string PAL_SHLIB_PREFIX = "lib"; 235 #if PLATFORM_OSX 236 const string PAL_SHLIB_SUFFIX = ".dylib"; 237 #else 238 const string PAL_SHLIB_SUFFIX = ".so"; 239 #endif 240 241 // Try prefix+name+suffix 242 hModule = LoadLibrary(PAL_SHLIB_PREFIX + moduleName + PAL_SHLIB_SUFFIX); 243 if (hModule != IntPtr.Zero) return hModule; 244 245 // Try name+suffix 246 hModule = LoadLibrary(moduleName + PAL_SHLIB_SUFFIX); 247 if (hModule != IntPtr.Zero) return hModule; 248 249 // Try prefix+name 250 hModule = LoadLibrary(PAL_SHLIB_PREFIX + moduleName); 251 if (hModule != IntPtr.Zero) return hModule; 252 #endif 253 return IntPtr.Zero; 254 } 255 LoadLibrary(string moduleName)256 internal static unsafe IntPtr LoadLibrary(string moduleName) 257 { 258 IntPtr hModule; 259 260 #if !PLATFORM_UNIX 261 hModule = Interop.mincore.LoadLibraryEx(moduleName, IntPtr.Zero, 0); 262 #else 263 hModule = Interop.Sys.LoadLibrary(moduleName); 264 #endif 265 266 return hModule; 267 } 268 FreeLibrary(IntPtr hModule)269 internal static unsafe void FreeLibrary(IntPtr hModule) 270 { 271 #if !PLATFORM_UNIX 272 Interop.mincore.FreeLibrary(hModule); 273 #else 274 Interop.Sys.FreeLibrary(hModule); 275 #endif 276 } 277 GetModuleName(ModuleFixupCell* pCell)278 private static unsafe string GetModuleName(ModuleFixupCell* pCell) 279 { 280 byte* pModuleName = (byte*)pCell->ModuleName; 281 return Encoding.UTF8.GetString(pModuleName, strlen(pModuleName)); 282 } 283 FixupModuleCell(ModuleFixupCell* pCell)284 internal static unsafe void FixupModuleCell(ModuleFixupCell* pCell) 285 { 286 string moduleName = GetModuleName(pCell); 287 IntPtr hModule = TryResolveModule(moduleName); 288 if (hModule != IntPtr.Zero) 289 { 290 var oldValue = Interlocked.CompareExchange(ref pCell->Handle, hModule, IntPtr.Zero); 291 if (oldValue != IntPtr.Zero) 292 { 293 // Some other thread won the race to fix it up. 294 FreeLibrary(hModule); 295 } 296 } 297 else 298 { 299 throw new DllNotFoundException(SR.Format(SR.Arg_DllNotFoundExceptionParameterized, moduleName)); 300 } 301 } 302 FixupMethodCell(IntPtr hModule, MethodFixupCell* pCell)303 internal static unsafe void FixupMethodCell(IntPtr hModule, MethodFixupCell* pCell) 304 { 305 byte* methodName = (byte*)pCell->MethodName; 306 307 #if !PLATFORM_UNIX 308 pCell->Target = Interop.mincore.GetProcAddress(hModule, methodName); 309 #else 310 pCell->Target = Interop.Sys.GetProcAddress(hModule, methodName); 311 #endif 312 if (pCell->Target == IntPtr.Zero) 313 { 314 string entryPointName = Encoding.UTF8.GetString(methodName, strlen(methodName)); 315 throw new EntryPointNotFoundException(SR.Format(SR.Arg_EntryPointNotFoundExceptionParameterized, entryPointName, GetModuleName(pCell->Module))); 316 } 317 } 318 strlen(byte* pString)319 internal static unsafe int strlen(byte* pString) 320 { 321 byte* p = pString; 322 while (*p != 0) p++; 323 return checked((int)(p - pString)); 324 } 325 CoTaskMemAllocAndZeroMemory(global::System.IntPtr size)326 internal unsafe static void* CoTaskMemAllocAndZeroMemory(global::System.IntPtr size) 327 { 328 void* ptr; 329 ptr = PInvokeMarshal.CoTaskMemAlloc((UIntPtr)(void*)size).ToPointer(); 330 331 // PInvokeMarshal.CoTaskMemAlloc will throw OOMException if out of memory 332 Debug.Assert(ptr != null); 333 334 Buffer.ZeroMemory((byte*)ptr, size.ToInt64()); 335 return ptr; 336 } 337 CoTaskMemFree(void* p)338 internal unsafe static void CoTaskMemFree(void* p) 339 { 340 PInvokeMarshal.CoTaskMemFree((IntPtr)p); 341 } 342 /// <summary> 343 /// Returns the stub to the pinvoke marshalling stub 344 /// </summary> GetStubForPInvokeDelegate(Delegate del)345 public static IntPtr GetStubForPInvokeDelegate(Delegate del) 346 { 347 return PInvokeMarshal.GetStubForPInvokeDelegate(del); 348 } 349 350 /// <summary> 351 /// Retrieve the corresponding P/invoke instance from the stub 352 /// </summary> GetPInvokeDelegateForStub(IntPtr pStub, RuntimeTypeHandle delegateType)353 public static Delegate GetPInvokeDelegateForStub(IntPtr pStub, RuntimeTypeHandle delegateType) 354 { 355 return PInvokeMarshal.GetPInvokeDelegateForStub(pStub, delegateType); 356 } 357 358 /// <summary> 359 /// Retrieves the function pointer for the current open static delegate that is being called 360 /// </summary> GetCurrentCalleeOpenStaticDelegateFunctionPointer()361 public static IntPtr GetCurrentCalleeOpenStaticDelegateFunctionPointer() 362 { 363 return PInvokeMarshal.GetCurrentCalleeOpenStaticDelegateFunctionPointer(); 364 } 365 366 /// <summary> 367 /// Retrieves the current delegate that is being called 368 /// </summary> 369 public static T GetCurrentCalleeDelegate<T>() where T : class // constraint can't be System.Delegate 370 { 371 return PInvokeMarshal.GetCurrentCalleeDelegate<T>(); 372 } 373 374 [StructLayout(LayoutKind.Sequential)] 375 internal unsafe struct ModuleFixupCell 376 { 377 public IntPtr Handle; 378 public IntPtr ModuleName; 379 } 380 381 [StructLayout(LayoutKind.Sequential)] 382 internal unsafe struct MethodFixupCell 383 { 384 public IntPtr Target; 385 public IntPtr MethodName; 386 public ModuleFixupCell* Module; 387 } 388 } 389 } 390