File: Symbols\PlatformInvokeInformation.cs
Web Access
Project: src\src\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj (Microsoft.CodeAnalysis)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Reflection;
using System.Runtime.InteropServices;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis
{
    /// <summary>
    /// Information that describes how a method from the underlying Platform is to be invoked.
    /// </summary>
    public sealed class DllImportData : Cci.IPlatformInvokeInformation
    {
        private readonly string? _moduleName;
        private readonly string? _entryPointName;            // null if unspecified, the name of the target method should be used
        private readonly MethodImportAttributes _flags;
 
        internal DllImportData(string? moduleName, string? entryPointName, MethodImportAttributes flags)
        {
            _moduleName = moduleName;
            _entryPointName = entryPointName;
            _flags = flags;
        }
 
        /// <summary>
        /// Module name. Null if value specified in the attribute is not valid.
        /// </summary>
        public string? ModuleName
        {
            get { return _moduleName; }
        }
 
        /// <summary>
        /// Name of the native entry point or null if not specified (the effective name is the same as the name of the target method).
        /// </summary>
        public string? EntryPointName
        {
            get { return _entryPointName; }
        }
 
        MethodImportAttributes Cci.IPlatformInvokeInformation.Flags
        {
            get { return _flags; }
        }
 
        /// <summary>
        /// Controls whether the <see cref="CharacterSet"/> field causes the common language runtime 
        /// to search an unmanaged DLL for entry-point names other than the one specified.
        /// </summary>
        public bool ExactSpelling
        {
            get
            {
                return (_flags & MethodImportAttributes.ExactSpelling) != 0;
            }
        }
 
        /// <summary>
        /// Indicates how to marshal string parameters and controls name mangling.
        /// </summary>
        public CharSet CharacterSet
        {
            get
            {
                switch (_flags & MethodImportAttributes.CharSetMask)
                {
                    case MethodImportAttributes.CharSetAnsi:
                        return CharSet.Ansi;
 
                    case MethodImportAttributes.CharSetUnicode:
                        return CharSet.Unicode;
 
                    case MethodImportAttributes.CharSetAuto:
                        return Cci.Constants.CharSet_Auto;
 
                    case 0:
                        return Cci.Constants.CharSet_None;
                }
 
                throw ExceptionUtilities.UnexpectedValue(_flags);
            }
        }
 
        /// <summary>
        /// Indicates whether the callee calls the SetLastError Win32 API function before returning from the attributed method.
        /// </summary>
        public bool SetLastError
        {
            get
            {
                return (_flags & MethodImportAttributes.SetLastError) != 0;
            }
        }
 
        /// <summary>
        /// Indicates the calling convention of an entry point.
        /// </summary>
        public CallingConvention CallingConvention
        {
            get
            {
                switch (_flags & MethodImportAttributes.CallingConventionMask)
                {
                    default:
                        return CallingConvention.Winapi;
 
                    case MethodImportAttributes.CallingConventionCDecl:
                        return CallingConvention.Cdecl;
 
                    case MethodImportAttributes.CallingConventionStdCall:
                        return CallingConvention.StdCall;
 
                    case MethodImportAttributes.CallingConventionThisCall:
                        return CallingConvention.ThisCall;
 
                    case MethodImportAttributes.CallingConventionFastCall:
                        return Cci.Constants.CallingConvention_FastCall;
                }
            }
        }
 
        /// <summary>
        /// Enables or disables best-fit mapping behavior when converting Unicode characters to ANSI characters.
        /// Null if not specified (the setting for the containing type or assembly should be used, <see cref="BestFitMappingAttribute"/>).
        /// </summary>
        public bool? BestFitMapping
        {
            get
            {
                switch (_flags & MethodImportAttributes.BestFitMappingMask)
                {
                    case MethodImportAttributes.BestFitMappingEnable:
                        return true;
 
                    case MethodImportAttributes.BestFitMappingDisable:
                        return false;
 
                    default:
                        return null;
                }
            }
        }
 
        /// <summary>
        /// Enables or disables the throwing of an exception on an unmappable Unicode character that is converted to an ANSI "?" character.
        /// Null if not specified.
        /// </summary>
        public bool? ThrowOnUnmappableCharacter
        {
            get
            {
                switch (_flags & MethodImportAttributes.ThrowOnUnmappableCharMask)
                {
                    case MethodImportAttributes.ThrowOnUnmappableCharEnable:
                        return true;
 
                    case MethodImportAttributes.ThrowOnUnmappableCharDisable:
                        return false;
 
                    default:
                        return null;
                }
            }
        }
 
        internal static MethodImportAttributes MakeFlags(bool exactSpelling, CharSet charSet, bool setLastError, CallingConvention callingConvention, bool? useBestFit, bool? throwOnUnmappable)
        {
            MethodImportAttributes result = 0;
            if (exactSpelling)
            {
                result |= MethodImportAttributes.ExactSpelling;
            }
 
            switch (charSet)
            {
                case CharSet.Ansi:
                    result |= MethodImportAttributes.CharSetAnsi;
                    break;
 
                case CharSet.Unicode:
                    result |= MethodImportAttributes.CharSetUnicode;
                    break;
 
                case Cci.Constants.CharSet_Auto:
                    result |= MethodImportAttributes.CharSetAuto;
                    break;
 
                    // Dev10: use default without reporting an error
            }
 
            if (setLastError)
            {
                result |= MethodImportAttributes.SetLastError;
            }
 
            switch (callingConvention)
            {
                default: // Dev10: uses default without reporting an error
                    result |= MethodImportAttributes.CallingConventionWinApi;
                    break;
 
                case CallingConvention.Cdecl:
                    result |= MethodImportAttributes.CallingConventionCDecl;
                    break;
 
                case CallingConvention.StdCall:
                    result |= MethodImportAttributes.CallingConventionStdCall;
                    break;
 
                case CallingConvention.ThisCall:
                    result |= MethodImportAttributes.CallingConventionThisCall;
                    break;
 
                case Cci.Constants.CallingConvention_FastCall:
                    result |= MethodImportAttributes.CallingConventionFastCall;
                    break;
            }
 
            if (throwOnUnmappable.HasValue)
            {
                if (throwOnUnmappable.Value)
                {
                    result |= MethodImportAttributes.ThrowOnUnmappableCharEnable;
                }
                else
                {
                    result |= MethodImportAttributes.ThrowOnUnmappableCharDisable;
                }
            }
 
            if (useBestFit.HasValue)
            {
                if (useBestFit.Value)
                {
                    result |= MethodImportAttributes.BestFitMappingEnable;
                }
                else
                {
                    result |= MethodImportAttributes.BestFitMappingDisable;
                }
            }
 
            return result;
        }
    }
}