diff --git a/docs/design/libraries/ComInterfaceGenerator/VTableStubs.md b/docs/design/libraries/ComInterfaceGenerator/VTableStubs.md new file mode 100644 index 0000000000000..21a10864759c8 --- /dev/null +++ b/docs/design/libraries/ComInterfaceGenerator/VTableStubs.md @@ -0,0 +1,413 @@ +# Generating Virtual Method Table Stubs + +As a building block for the COM interface source generator, we've decided to build a source generator that enables developers to mark that a given interface method should invoke a function pointer at a particular offset into an unmanaged virtual method table, or vtable. We've decided to build this generator as a building block for a few reasons: + +1. As part of the migration of dotnet/runtime to use source-generated P/Invokes, we encountered a few scenarios, particularly in the networking stacks, where non-blittable delegate interop was used because the native APIs do not have static entry points. For at least one of these scenarios, MsQuic, the native library provides a table of function pointers. From our experience, this mechanism for versioning is not uncommon and we feel that supporting native libraries that use a versioning scheme similar to this model is worthwhile for us to support. +2. There are native APIs that we are likely to interoperate with in the future that use native vtables but are not COM-oriented. In particular, the Java Native Interface API, which both dotnet/runtime and xamarin/java.interop interface with in various capacities, uses a vtable model to support exposing their APIs to C and C++. Additionally, its API does not conform to a COM-style IUnknown-based API. +3. Some COM-style APIs have some corner cases with non-COM-style interfaces. Specifically, some corners of the DirectX APIs are still vtable-based, but do not implement IUnknown. Providing this building block will allow developers to more easily consume these APIs with similar gestures as the rest of the DirectX API surface. +4. Our future COM interface source generator can build on this building block to provide defaults while allowing developers to use the features of this generator to override any default settings provided by the COM generator. + +## Defined types + +To support this generator, we will define the following APIs. + +The `VirtualMethodIndexAttribute` can be applied to an interface method to trigger the generator. This method will provide the index into the vtable for the method, whether or not the method implicitly takes the native `this` pointer, and which marshalling directions to support. It also has many of the same members as `LibraryImportAttribute` to consistently provide the same marshalling support across source-generated marshalling. + +```csharp +namespace System.Runtime.InteropServices; + +[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] +public class VirtualMethodIndexAttribute : Attribute +{ + public VirtualMethodIndexAttribute(int index) + { + Index = index; + } + + public int Index { get; } + + public bool ImplicitThisParameter { get; set; } = true; + + public MarshalDirection Direction { get; set; } = MarshalDirection.Bidirectional; + + /// + /// Gets or sets how to marshal string arguments to the method. + /// + /// + /// If this field is set to a value other than , + /// must not be specified. + /// + public StringMarshalling StringMarshalling { get; set; } + + /// + /// Gets or sets the used to control how string arguments to the method are marshalled. + /// + /// + /// If this field is specified, must not be specified + /// or must be set to . + /// + public Type? StringMarshallingCustomType { get; set; } + + /// + /// Gets or sets whether the callee sets an error (SetLastError on Windows or errno + /// on other platforms) before returning from the attributed method. + /// + public bool SetLastError { get; set; } +} + +``` + +New interfaces will be defined and used by the source generator to fetch the native `this` pointer and the vtable that the function pointer is stored in. These interfaces are designed to provide an API that various native platforms, like COM, WinRT, or Swift, could use to provide support for multiple managed interface wrappers from a single native object. In particular, these interfaces are designed to ensure it is possible support a managed gesture to do an unmanaged "type cast" (i.e., `QueryInterface` in the COM and WinRT worlds). + +```csharp +namespace System.Runtime.InteropServices; + +public readonly ref struct VirtualMethodTableInfo +{ + public VirtualMethodTableInfo(IntPtr thisPointer, ReadOnlySpan virtualMethodTable) + { + ThisPointer = thisPointer; + VirtualMethodTable = virtualMethodTable; + } + + public IntPtr ThisPointer { get; } + public ReadOnlySpan VirtualMethodTable { get; } + + public void Deconstruct(out IntPtr thisPointer, out ReadOnlySpan virtualMethodTable) // This method allows tuple-style `var (thisPtr, vtable) = virtualMethodTableInfo;` statements from this type. + { + thisPointer = ThisPointer; + virtualMethodTable = VirtualMethodTable; + } +} + +public interface IUnmanagedVirtualMethodTableProvider where T : IEquatable +{ + protected VirtualMethodTableInfo GetVirtualMethodTableInfoForKey(T typeKey); + + public sealed VirtualMethodTableInfo GetVirtualMethodTableInfoForKey() + where TUnmanagedInterfaceType : IUnmanagedInterfaceType + { + return GetVirtualMethodTableInfoForKey(TUnmanagedInterfaceType.TypeKey); + } +} + +public interface IUnmanagedInterfaceType where T : IEquatable +{ + public abstract static T TypeKey { get; } +} +``` + +## Required API Shapes + +The user will be required to implement `IUnmanagedVirtualMethodTableProvider` on the type that provides the method tables, and `IUnmanagedInterfaceType` on the type that defines the unmanaged interface. The `T` types must match between the two interfaces. This mechanism is designed to enable each native API platform to provide their own casting key, for example `IID`s in COM, without interfering with each other or requiring using reflection-based types like `System.Type`. + +## Example Usage + +### Flat function table + +In this example, the native API provides a flat table of functions based on the provided version. + +```cpp +// NativeAPI.cpp + +struct NativeAPI +{ + int(*getVersion)(); + int(*add)(int x, int y); + int(*multiply)(int x, int y); +}; + +namespace +{ + int getVersion() + { + return 1; + } + int add(int x, int y) + { + return x + y; + } + int multiply(int x, int y) + { + return x * y; + } + const NativeAPI g_nativeAPI = { + &getVersion, + &add, + &multiply + }; +} + +extern "C" bool GetNativeAPI(int version, NativeAPI const** ppNativeAPI) +{ + if (version > getVersion()) + { + *ppNativeAPI = nullptr; + return false; + } + *ppNativeAPI = &g_nativeAPI; + return true; +} + +``` + +```csharp +// User-written code +// NativeAPI.cs +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly:DisableRuntimeMarshalling] + +// Define the interface of the native API +partial interface INativeAPI : IUnmanagedInterfaceType +{ + // There is no concept of casting for this API, but providing a type key is still required by the generator. + // Use an empty readonly record struct to provide a type that implements IEquatable but contains no data. + static NoCasting IUnmanagedInterfaceType.TypeKey => default; + + [VirtualMethodIndex(0, ImplicitThisParameter = false, Direction = CustomTypeMarshallerDirection.In)] + int GetVersion(); + + [VirtualMethodIndex(1, ImplicitThisParameter = false, Direction = CustomTypeMarshallerDirection.In)] + int Add(int x, int y); + + [VirtualMethodIndex(2, ImplicitThisParameter = false, Direction = CustomTypeMarshallerDirection.In)] + int Multiply(int x, int y); +} + +// Define the key for native "casting" support for our scenario +readonly record struct NoCasting {} + +// Define our runtime wrapper type for the native interface. +unsafe class NativeAPI : IUnmanagedVirtualMethodTableProvider, INativeAPI.Native +{ + private CNativeAPI* _nativeAPI; + + public NativeAPI() + { + if (!CNativeAPI.GetNativeAPI(1, out _nativeAPI)) + { + throw new InvalidOperationException(); + } + } + + VirtualMethodTableInfo IUnmanagedVirtualMethodTableProvider.GetVirtualMethodTableInfoForKey(NoCasting _) + { + return new(IntPtr.Zero, MemoryMarshal.Cast(new ReadOnlySpan(_nativeAPI, 1))); + } +} + +// This struct represent a flat table of function pointers that implements the native API. +// This can either be returned by the API (MSQuic) or be constructed manually from calling +// a method that returns function pointers and be used as a cache (OpenGL and Vulkan) +unsafe partial struct CNativeAPI +{ + IntPtr getVersion; + IntPtr add; + IntPtr multiply; + + [LibraryImport(nameof(NativeAPI))] + public static partial bool GetNativeAPI(int version, out CNativeAPI* ppNativeAPI); +}; + +// Generated code for VirtualMethodIndex generator + +// NativeInterfaces.g.cs +partial interface INativeAPI +{ + [DynamicInterfaceCastableImplementation] + partial interface Native : INativeAPI + { + } +} + +// ManagedToNativeStubs.g.cs +partial interface INativeAPI +{ + unsafe partial interface Native + { + int INativeAPI.GetVersion() + { + var (_, vtable) = ((IUnmanagedVirtualMethodTableProvider)this).GetVirtualMethodTableInfoForKey(); + int retVal; + retVal = ((delegate* unmanaged)vtable[0])(); + return retVal; + } + } +} +partial interface INativeAPI +{ + unsafe partial interface Native + { + int INativeAPI.Add(int x, int y) + { + var (_, vtable) = ((IUnmanagedVirtualMethodTableProvider)this).GetVirtualMethodTableInfoForKey(); + int retVal; + retVal = ((delegate* unmanaged)vtable[1])(x, y); + return retVal; + } + } +} +partial interface INativeAPI +{ + unsafe partial interface Native + { + int INativeAPI.Multiply(int x, int y) + { + var (_, vtable) = ((IUnmanagedVirtualMethodTableProvider)this).GetVirtualMethodTableInfoForKey(); + int retVal; + retVal = ((delegate* unmanaged)vtable[2])(x, y); + return retVal; + } + } +} + +// LibraryImport-generated code omitted for brevity +``` + +As this generator is primarily designed to provide building blocks for future work, it has a larger requirement on user-written code. In particular, this generator does not provide any support for authoring a runtime wrapper object that stores the native pointers for the underlying object or the virtual method table. However, this lack of support also provides significant flexibility for developers. The only requirement for the runtime wrapper object type is that it implements `IUnmanagedVirtualMethodTableProvider` with a `T` matching the `TypeKey` type of the native interface. + +The emitted interface implementation can be used in two ways: + +1. The user's runtime wrapper object can directly implement the emitted `Native` interface. This method works for cases where all interfaces are statically known to exist (interfaces are not conditionally implemented on each object). +2. The user's runtime wrapper object can implement `IDynamicInterfaceCastable` and can return the handle of `INativeAPI.Native` when user code casts the wrapper to `INativeAPI`. This style is more commonly used for COM-style APIs. + +### COM interface + +```cpp +// C++ code +struct IUnknown +{ + virtual HRESULT QueryInterface(REFIID riid, void **ppvObject) = 0; + virtual ULONG AddRef() = 0; + virtual ULONG Release() = 0; +}; + +``` +```csharp +// User-defined C# code +using System; +using System.Runtime.InteropServices; + +interface IUnknown: IUnmanagedInterfaceType +{ + static Guid IUnmanagedTypeInterfaceType.TypeKey => Guid.Parse("00000000-0000-0000-C000-000000000046"); + + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvStdcall), typeof(CallConvMemberFunction) })] + [VirtualMethodIndex(0)] + int QueryInterface(in Guid riid, out IntPtr ppvObject); + + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvStdcall), typeof(CallConvMemberFunction) })] + [VirtualMethodIndex(1)] + uint AddRef(); + + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvStdcall), typeof(CallConvMemberFunction) })] + [VirtualMethodIndex(2)] + uint Release(); +} + +class BaseIUnknownComObject : IUnmanagedVirtualMethodTableProvider, IDynamicInterfaceCastable +{ + private IntPtr _unknownPtr; + + public BaseIUnknownComObject(IntPtr unknown) + { + _unknownPtr = unknown; + } + + unsafe VirtualMethodTableInfo IUnmanagedVirtualMethodTableProvider.GetVirtualMethodTableInfoForKey(Guid iid) + { + if (iid == IUnknown.TypeKey) + { + return new VirtualMethodTableInfo(_unknownPtr, new ReadOnlySpan(**(IntPtr***)_unknownPtr), 3); + } + return default; + } + + RuntimeTypeHandle IDynamicInterfaceCastable.GetInterfaceImplementation(RuntimeTypeHandle interfaceType) + { + if (Type.GetTypeFromHandle(interfaceType) == typeof(IUnknown)) + { + return typeof(IUnknown.Native).TypeHandle; + } + return default; + } + + bool IDynamicInterfaceCastable.IsInterfaceImplemented(RuntimeTypeHandle interfaceType, bool throwIfNotImplemented) + { + return Type.GetTypeFromHandle(interfaceType) == typeof(IUnknown); + } +} + +// Generated code for VirtualMethodIndex generator + +// NativeInterfaces.g.cs +partial interface IUnknown +{ + [DynamicInterfaceCastableImplementation] + partial interface Native : IUnknown + { + } +} + +// ManagedToNativeStubs.g.cs +partial interface IUnknown +{ + partial interface Native + { + int IUnknown.QueryInterface(in Guid riid, out IntPtr ppvObject) + { + var (thisPtr, vtable) = ((IUnmanagedVirtualMethodTableProvider)this).GetVirtualMethodTableInfoForKey(); + int retVal; + fixed (Guid* riid__gen_native = &riid) + fixed (IntPtr* ppvObject__gen_native = &ppvObject) + { + retVal = ((delegate* unmanaged[Stdcall, MemberFunction])vtable[0])(thisPtr, riid__gen_native, ppvObject__gen_native); + } + return retVal; + } + } +} +partial interface IUnknown +{ + partial interface Native + { + uint IUnknown.AddRef() + { + var (thisPtr, vtable) = ((IUnmanagedVirtualMethodTableProvider)this).GetVirtualMethodTableInfoForKey(); + uint retVal; + retVal = ((delegate* unmanaged[Stdcall, MemberFunction])vtable[1])(thisPtr); + return retVal; + } + } +} +partial interface IUnknown +{ + partial interface Native + { + uint IUnknown.Release() + { + var (thisPtr, vtable) = ((IUnmanagedVirtualMethodTableProvider)this).GetVirtualMethodTableInfoForKey(); + uint retVal; + retVal = ((delegate* unmanaged[Stdcall, MemberFunction])vtable[2])(thisPtr); + return retVal; + } + } +} + +// Native-To-Managed code omitted as the design has not been finalized yet. +``` + +This example shows how we can build COM support on top of the vtable stub generator. The generator will support specifying a custom calling convention using the already-existing `UnmanagedCallConvAttribute`, so it will automatically support forwarding any calling conventions we implement with our extensible calling convention support to the function pointer signature. + +## FAQ + +- Why emit a nested interface instead of a DIM on the existing interface? + - By emitting a nested interface, we enable flexibility in the implementation of the user-defined interface without our implementations getting in the way. With the current design, a managed implementation of a given interface would require the user to implement all members. If we emitted the member implementations directly as DIM implementations, then the compiler would happily allow a developer to only override one method and leave the rest using the native implementation, which would make the development experience of a managed implementation more difficult as there would be no IDE/compiler assistance to fully implement the contract. + +## Open Questions + +- Should we automatically apply the `[DynamicInterfaceCastableImplementation]` attribute to the generated `Native` interface? + - It is a nice convenience, but it isn't applicable in all scenarios and bloats the metadata size. Additionally, since the generated interface is `partial`, we could direct users to add it themselves to the generated interface. + diff --git a/eng/testing/tests.props b/eng/testing/tests.props index 7ed95b94326e3..525e2c0e2b524 100644 --- a/eng/testing/tests.props +++ b/eng/testing/tests.props @@ -27,7 +27,7 @@ - + + RS2008;$(NoWarn) + cs + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGeneratorHelpers.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGeneratorHelpers.cs new file mode 100644 index 0000000000000..f9f0bf684ff82 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGeneratorHelpers.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.CodeAnalysis; + +namespace Microsoft.Interop +{ + internal static class ComInterfaceGeneratorHelpers + { + public static MarshallingGeneratorFactoryKey<(TargetFramework, Version)> CreateGeneratorFactory(StubEnvironment env) + { + IMarshallingGeneratorFactory generatorFactory; + + // If we're in a "supported" scenario, then emit a diagnostic as our final fallback. + generatorFactory = new UnsupportedMarshallingFactory(); + + generatorFactory = new NoMarshallingInfoErrorMarshallingFactory(generatorFactory); + + // The presence of System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute is tied to TFM, + // so we use TFM in the generator factory key instead of the Compilation as the compilation changes on every keystroke. + IAssemblySymbol coreLibraryAssembly = env.Compilation.GetSpecialType(SpecialType.System_Object).ContainingAssembly; + ITypeSymbol? disabledRuntimeMarshallingAttributeType = coreLibraryAssembly.GetTypeByMetadataName(TypeNames.System_Runtime_CompilerServices_DisableRuntimeMarshallingAttribute); + bool runtimeMarshallingDisabled = disabledRuntimeMarshallingAttributeType is not null + && env.Compilation.Assembly.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, disabledRuntimeMarshallingAttributeType)); + + // Since the char type can go into the P/Invoke signature here, we can only use it when + // runtime marshalling is disabled. + generatorFactory = new CharMarshallingGeneratorFactory(generatorFactory, useBlittableMarshallerForUtf16: runtimeMarshallingDisabled); + + InteropGenerationOptions interopGenerationOptions = new(UseMarshalType: true); + generatorFactory = new MarshalAsMarshallingGeneratorFactory(interopGenerationOptions, generatorFactory); + + IMarshallingGeneratorFactory elementFactory = new AttributedMarshallingModelGeneratorFactory( + // Since the char type in an array will not be part of the P/Invoke signature, we can + // use the regular blittable marshaller in all cases. + new CharMarshallingGeneratorFactory(generatorFactory, useBlittableMarshallerForUtf16: true), + new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, MarshalMode.ElementIn, MarshalMode.ElementRef, MarshalMode.ElementOut)); + // We don't need to include the later generator factories for collection elements + // as the later generator factories only apply to parameters. + generatorFactory = new AttributedMarshallingModelGeneratorFactory( + generatorFactory, + elementFactory, + new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, MarshalMode.ManagedToUnmanagedIn, MarshalMode.ManagedToUnmanagedRef, MarshalMode.ManagedToUnmanagedOut)); + + generatorFactory = new ByValueContentsMarshalKindValidator(generatorFactory); + + return MarshallingGeneratorFactoryKey.Create((env.TargetFramework, env.TargetFrameworkVersion), generatorFactory); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Comparers.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Comparers.cs new file mode 100644 index 0000000000000..3d710b6290e86 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Comparers.cs @@ -0,0 +1,70 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; + +namespace Microsoft.Interop +{ + internal static class Comparers + { + /// + /// Comparer for an individual generated stub source as a syntax tree and the generated diagnostics for the stub. + /// + public static readonly IEqualityComparer<(MemberDeclarationSyntax Syntax, ImmutableArray Diagnostics)> GeneratedSyntax = new CustomValueTupleElementComparer>(SyntaxEquivalentComparer.Instance, new ImmutableArraySequenceEqualComparer(EqualityComparer.Default)); + } + + /// + /// Generic comparer to compare two instances element by element. + /// + /// The type of immutable array element. + internal sealed class ImmutableArraySequenceEqualComparer : IEqualityComparer> + { + private readonly IEqualityComparer _elementComparer; + + /// + /// Creates an with a custom comparer for the elements of the collection. + /// + /// The comparer instance for the collection elements. + public ImmutableArraySequenceEqualComparer(IEqualityComparer elementComparer) + { + _elementComparer = elementComparer; + } + + public bool Equals(ImmutableArray x, ImmutableArray y) + { + return x.SequenceEqual(y, _elementComparer); + } + + public int GetHashCode(ImmutableArray obj) + { + throw new UnreachableException(); + } + } + + internal sealed class CustomValueTupleElementComparer : IEqualityComparer<(T, U)> + { + private readonly IEqualityComparer _item1Comparer; + private readonly IEqualityComparer _item2Comparer; + + public CustomValueTupleElementComparer(IEqualityComparer item1Comparer, IEqualityComparer item2Comparer) + { + _item1Comparer = item1Comparer; + _item2Comparer = item2Comparer; + } + + public bool Equals((T, U) x, (T, U) y) + { + return _item1Comparer.Equals(x.Item1, y.Item1) && _item2Comparer.Equals(x.Item2, y.Item2); + } + + public int GetHashCode((T, U) obj) + { + throw new UnreachableException(); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs new file mode 100644 index 0000000000000..e4f8686445ec3 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs @@ -0,0 +1,303 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Microsoft.Interop +{ + /// + /// Class for reporting diagnostics in the library import generator + /// + public class GeneratorDiagnostics : IGeneratorDiagnostics + { + public class Ids + { + // SYSLIB1050-SYSLIB1059 are reserved for source-generated Interop + public const string Prefix = "SYSLIB"; + public const string InvalidLibraryImportAttributeUsage = Prefix + "1050"; + public const string TypeNotSupported = Prefix + "1051"; + public const string ConfigurationNotSupported = Prefix + "1052"; + } + + private const string Category = "ComInterfaceGenerator"; + + public static readonly DiagnosticDescriptor InvalidAttributedMethodSignature = + new DiagnosticDescriptor( + Ids.InvalidLibraryImportAttributeUsage, + GetResourceString(nameof(SR.InvalidLibraryImportAttributeUsageTitle)), + GetResourceString(nameof(SR.InvalidAttributedMethodSignatureMessage)), + Category, + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: GetResourceString(nameof(SR.InvalidAttributedMethodDescription))); + + public static readonly DiagnosticDescriptor InvalidAttributedMethodContainingTypeMissingModifiers = + new DiagnosticDescriptor( + Ids.InvalidLibraryImportAttributeUsage, + GetResourceString(nameof(SR.InvalidLibraryImportAttributeUsageTitle)), + GetResourceString(nameof(SR.InvalidAttributedMethodContainingTypeMissingModifiersMessage)), + Category, + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: GetResourceString(nameof(SR.InvalidAttributedMethodDescription))); + + public static readonly DiagnosticDescriptor InvalidStringMarshallingConfiguration = + new DiagnosticDescriptor( + Ids.InvalidLibraryImportAttributeUsage, + GetResourceString(nameof(SR.InvalidLibraryImportAttributeUsageTitle)), + GetResourceString(nameof(SR.InvalidStringMarshallingConfigurationMessage)), + Category, + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: GetResourceString(nameof(SR.InvalidStringMarshallingConfigurationDescription))); + + public static readonly DiagnosticDescriptor ParameterTypeNotSupported = + new DiagnosticDescriptor( + Ids.TypeNotSupported, + GetResourceString(nameof(SR.TypeNotSupportedTitle)), + GetResourceString(nameof(SR.TypeNotSupportedMessageParameter)), + Category, + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: GetResourceString(nameof(SR.TypeNotSupportedDescription))); + + public static readonly DiagnosticDescriptor ReturnTypeNotSupported = + new DiagnosticDescriptor( + Ids.TypeNotSupported, + GetResourceString(nameof(SR.TypeNotSupportedTitle)), + GetResourceString(nameof(SR.TypeNotSupportedMessageReturn)), + Category, + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: GetResourceString(nameof(SR.TypeNotSupportedDescription))); + + public static readonly DiagnosticDescriptor ParameterTypeNotSupportedWithDetails = + new DiagnosticDescriptor( + Ids.TypeNotSupported, + GetResourceString(nameof(SR.TypeNotSupportedTitle)), + GetResourceString(nameof(SR.TypeNotSupportedMessageParameterWithDetails)), + Category, + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: GetResourceString(nameof(SR.TypeNotSupportedDescription))); + + public static readonly DiagnosticDescriptor ReturnTypeNotSupportedWithDetails = + new DiagnosticDescriptor( + Ids.TypeNotSupported, + GetResourceString(nameof(SR.TypeNotSupportedTitle)), + GetResourceString(nameof(SR.TypeNotSupportedMessageReturnWithDetails)), + Category, + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: GetResourceString(nameof(SR.TypeNotSupportedDescription))); + + public static readonly DiagnosticDescriptor ParameterConfigurationNotSupported = + new DiagnosticDescriptor( + Ids.ConfigurationNotSupported, + GetResourceString(nameof(SR.ConfigurationNotSupportedTitle)), + GetResourceString(nameof(SR.ConfigurationNotSupportedMessageParameter)), + Category, + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: GetResourceString(nameof(SR.ConfigurationNotSupportedDescription))); + + public static readonly DiagnosticDescriptor ReturnConfigurationNotSupported = + new DiagnosticDescriptor( + Ids.ConfigurationNotSupported, + GetResourceString(nameof(SR.ConfigurationNotSupportedTitle)), + GetResourceString(nameof(SR.ConfigurationNotSupportedMessageReturn)), + Category, + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: GetResourceString(nameof(SR.ConfigurationNotSupportedDescription))); + + public static readonly DiagnosticDescriptor ConfigurationNotSupported = + new DiagnosticDescriptor( + Ids.ConfigurationNotSupported, + GetResourceString(nameof(SR.ConfigurationNotSupportedTitle)), + GetResourceString(nameof(SR.ConfigurationNotSupportedMessage)), + Category, + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: GetResourceString(nameof(SR.ConfigurationNotSupportedDescription))); + + public static readonly DiagnosticDescriptor ConfigurationValueNotSupported = + new DiagnosticDescriptor( + Ids.ConfigurationNotSupported, + GetResourceString(nameof(SR.ConfigurationNotSupportedTitle)), + GetResourceString(nameof(SR.ConfigurationNotSupportedMessageValue)), + Category, + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: GetResourceString(nameof(SR.ConfigurationNotSupportedDescription))); + + public static readonly DiagnosticDescriptor MarshallingAttributeConfigurationNotSupported = + new DiagnosticDescriptor( + Ids.ConfigurationNotSupported, + GetResourceString(nameof(SR.ConfigurationNotSupportedTitle)), + GetResourceString(nameof(SR.ConfigurationNotSupportedMessageMarshallingInfo)), + Category, + DiagnosticSeverity.Error, + isEnabledByDefault: true, + description: GetResourceString(nameof(SR.ConfigurationNotSupportedDescription))); + + private readonly List _diagnostics = new List(); + + public IEnumerable Diagnostics => _diagnostics; + + /// + /// Report diagnostic for invalid configuration for string marshalling. + /// + /// Attribute specifying the invalid configuration + /// Name of the method + /// Specific reason the configuration is invalid + public void ReportInvalidStringMarshallingConfiguration( + AttributeData attributeData, + string methodName, + string detailsMessage) + { + _diagnostics.Add( + attributeData.CreateDiagnostic( + GeneratorDiagnostics.InvalidStringMarshallingConfiguration, + methodName, + detailsMessage)); + } + + /// + /// Report diagnostic for configuration that is not supported by the DLL import source generator + /// + /// Attribute specifying the unsupported configuration + /// Name of the configuration + /// [Optiona] Unsupported configuration value + public void ReportConfigurationNotSupported( + AttributeData attributeData, + string configurationName, + string? unsupportedValue = null) + { + if (unsupportedValue == null) + { + _diagnostics.Add( + attributeData.CreateDiagnostic( + GeneratorDiagnostics.ConfigurationNotSupported, + configurationName)); + } + else + { + _diagnostics.Add( + attributeData.CreateDiagnostic( + GeneratorDiagnostics.ConfigurationValueNotSupported, + unsupportedValue, + configurationName)); + } + } + + /// + /// Report diagnostic for marshalling of a parameter/return that is not supported + /// + /// Method with the parameter/return + /// Type info for the parameter/return + /// [Optional] Specific reason for lack of support + public void ReportMarshallingNotSupported( + MethodSignatureDiagnosticLocations method, + TypePositionInfo info, + string? notSupportedDetails) + { + Location diagnosticLocation = Location.None; + string elementName = string.Empty; + + if (info.IsManagedReturnPosition) + { + diagnosticLocation = method.FallbackLocation; + elementName = method.MethodIdentifier; + } + else + { + Debug.Assert(info.ManagedIndex <= method.ManagedParameterLocations.Length); + diagnosticLocation = method.ManagedParameterLocations[info.ManagedIndex]; + elementName = info.InstanceIdentifier; + } + + if (!string.IsNullOrEmpty(notSupportedDetails)) + { + // Report the specific not-supported reason. + if (info.IsManagedReturnPosition) + { + _diagnostics.Add( + diagnosticLocation.CreateDiagnostic( + GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails, + notSupportedDetails!, + elementName)); + } + else + { + _diagnostics.Add( + diagnosticLocation.CreateDiagnostic( + GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails, + notSupportedDetails!, + elementName)); + } + } + else if (info.MarshallingAttributeInfo is MarshalAsInfo) + { + // Report that the specified marshalling configuration is not supported. + // We don't forward marshalling attributes, so this is reported differently + // than when there is no attribute and the type itself is not supported. + if (info.IsManagedReturnPosition) + { + _diagnostics.Add( + diagnosticLocation.CreateDiagnostic( + GeneratorDiagnostics.ReturnConfigurationNotSupported, + nameof(System.Runtime.InteropServices.MarshalAsAttribute), + elementName)); + } + else + { + _diagnostics.Add( + diagnosticLocation.CreateDiagnostic( + GeneratorDiagnostics.ParameterConfigurationNotSupported, + nameof(System.Runtime.InteropServices.MarshalAsAttribute), + elementName)); + } + } + else + { + // Report that the type is not supported + if (info.IsManagedReturnPosition) + { + _diagnostics.Add( + diagnosticLocation.CreateDiagnostic( + GeneratorDiagnostics.ReturnTypeNotSupported, + info.ManagedType.DiagnosticFormattedName, + elementName)); + } + else + { + _diagnostics.Add( + diagnosticLocation.CreateDiagnostic( + GeneratorDiagnostics.ParameterTypeNotSupported, + info.ManagedType.DiagnosticFormattedName, + elementName)); + } + } + } + + public void ReportInvalidMarshallingAttributeInfo( + AttributeData attributeData, + string reasonResourceName, + params string[] reasonArgs) + { + _diagnostics.Add( + attributeData.CreateDiagnostic( + GeneratorDiagnostics.MarshallingAttributeConfigurationNotSupported, + new LocalizableResourceString(reasonResourceName, SR.ResourceManager, typeof(FxResources.Microsoft.Interop.ComInterfaceGenerator.SR), reasonArgs))); + } + private static LocalizableResourceString GetResourceString(string resourceName) + { + return new LocalizableResourceString(resourceName, SR.ResourceManager, typeof(FxResources.Microsoft.Interop.ComInterfaceGenerator.SR)); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/LanguageSupport.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/LanguageSupport.cs new file mode 100644 index 0000000000000..2cf6b88120615 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/LanguageSupport.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Types defined to enable language support of various features +// in the source generator. +namespace System.Runtime.CompilerServices +{ + // Define IsExternalInit type to support records. + internal sealed class IsExternalInit + { } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ManagedToNativeVTableMethodGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ManagedToNativeVTableMethodGenerator.cs new file mode 100644 index 0000000000000..386ab7147c5b2 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ManagedToNativeVTableMethodGenerator.cs @@ -0,0 +1,263 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace Microsoft.Interop +{ + /// + /// Base code generator for generating the body of a source-generated P/Invoke and providing customization for how to invoke/define the native method. + /// + /// + /// This type enables multiple code generators for P/Invoke-style marshalling + /// to reuse the same basic method body, but with different designs of how to emit the target native method. + /// This enables users to write code generators that work with slightly different semantics. + /// For example, the source generator for [LibraryImport] emits the target P/Invoke as + /// a local function inside the generated stub body. + /// However, other managed-to-native code generators using a P/Invoke style might want to define + /// the target DllImport outside of the stub as a static non-local function or as a function pointer field. + /// This refactoring allows the code generator to have control over where the target method is declared + /// and how it is declared. + /// + internal sealed class ManagedToNativeVTableMethodGenerator + { + private const string ReturnIdentifier = "__retVal"; + private const string LastErrorIdentifier = "__lastError"; + private const string InvokeSucceededIdentifier = "__invokeSucceeded"; + private const string NativeThisParameterIdentifier = "__this"; + private const string VirtualMethodTableIdentifier = $"__vtable{StubCodeContext.GeneratedNativeIdentifierSuffix}"; + + // Error code representing success. This maps to S_OK for Windows HRESULT semantics and 0 for POSIX errno semantics. + private const int SuccessErrorCode = 0; + private readonly bool _setLastError; + private readonly BoundGenerators _marshallers; + + private readonly ManagedToNativeStubCodeContext _context; + + public ManagedToNativeVTableMethodGenerator( + TargetFramework targetFramework, + Version targetFrameworkVersion, + ImmutableArray argTypes, + bool setLastError, + bool implicitThis, + Action marshallingNotSupportedCallback, + IMarshallingGeneratorFactory generatorFactory) + { + _setLastError = setLastError; + if (implicitThis) + { + ImmutableArray.Builder newArgTypes = ImmutableArray.CreateBuilder(argTypes.Length + 1); + newArgTypes.Add(new TypePositionInfo(SpecialTypeInfo.IntPtr, NoMarshallingInfo.Instance) + { + InstanceIdentifier = NativeThisParameterIdentifier, + NativeIndex = 0 + }); + foreach (var arg in argTypes) + { + newArgTypes.Add(arg with + { + NativeIndex = arg.NativeIndex switch + { + TypePositionInfo.UnsetIndex or TypePositionInfo.ReturnIndex => arg.NativeIndex, + int index => index + 1 + } + }); + } + argTypes = newArgTypes.ToImmutableArray(); + } + + _context = new ManagedToNativeStubCodeContext(targetFramework, targetFrameworkVersion, ReturnIdentifier, ReturnIdentifier); + _marshallers = new BoundGenerators(argTypes, CreateGenerator); + + if (_marshallers.ManagedReturnMarshaller.Generator.UsesNativeIdentifier(_marshallers.ManagedReturnMarshaller.TypeInfo, _context)) + { + // If we need a different native return identifier, then recreate the context with the correct identifier before we generate any code. + _context = new ManagedToNativeStubCodeContext(targetFramework, targetFrameworkVersion, ReturnIdentifier, $"{ReturnIdentifier}{StubCodeContext.GeneratedNativeIdentifierSuffix}"); + } + + IMarshallingGenerator CreateGenerator(TypePositionInfo p) + { + try + { + // TODO: Remove once helper types (like ArrayMarshaller) are part of the runtime + // This check is to help with enabling the source generator for runtime libraries without making each + // library directly reference System.Memory and System.Runtime.CompilerServices.Unsafe unless it needs to + if (p.MarshallingAttributeInfo is MissingSupportMarshallingInfo + && (targetFramework == TargetFramework.Net && targetFrameworkVersion.Major >= 7)) + { + throw new MarshallingNotSupportedException(p, _context); + } + + return generatorFactory.Create(p, _context); + } + catch (MarshallingNotSupportedException e) + { + marshallingNotSupportedCallback(p, e); + return new Forwarder(); + } + } + } + + /// + /// Generate the method body of the p/invoke stub. + /// + /// Name of the target DllImport function to invoke + /// Method body of the p/invoke stub + /// + /// The generated code assumes it will be in an unsafe context. + /// + public BlockSyntax GenerateStubBody(int index, ImmutableArray callConv, TypeSyntax containingTypeName, ManagedTypeInfo typeKeyType) + { + var setupStatements = new List + { + // var (, ) = ((IUnmanagedVirtualMethodTableProvider<>)this).GetVirtualMethodTableInfoForKey<>(); + ExpressionStatement( + AssignmentExpression( + SyntaxKind.SimpleAssignmentExpression, + DeclarationExpression( + IdentifierName("var"), + ParenthesizedVariableDesignation( + SeparatedList( + new[]{ + SingleVariableDesignation( + Identifier(NativeThisParameterIdentifier)), + SingleVariableDesignation( + Identifier(VirtualMethodTableIdentifier))}))), + InvocationExpression( + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + ParenthesizedExpression( + CastExpression( + GenericName( + Identifier(TypeNames.IUnmanagedVirtualMethodTableProvider)) + .WithTypeArgumentList( + TypeArgumentList( + SingletonSeparatedList(typeKeyType.Syntax))), + ThisExpression())), + GenericName( + Identifier("GetVirtualMethodTableInfoForKey"), + TypeArgumentList( + SingletonSeparatedList(containingTypeName))))) + .WithArgumentList( + ArgumentList()))) + }; + + GeneratedStatements statements = GeneratedStatements.Create( + _marshallers, + _context, + CreateFunctionPointerExpression( + // [] + ElementAccessExpression(IdentifierName(VirtualMethodTableIdentifier), + BracketedArgumentList(SingletonSeparatedList( + Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(index)))))), + callConv)); + bool shouldInitializeVariables = !statements.GuaranteedUnmarshal.IsEmpty || !statements.Cleanup.IsEmpty; + VariableDeclarations declarations = VariableDeclarations.GenerateDeclarationsForManagedToNative(_marshallers, _context, shouldInitializeVariables); + + + if (_setLastError) + { + // Declare variable for last error + setupStatements.Add(MarshallerHelpers.Declare( + PredefinedType(Token(SyntaxKind.IntKeyword)), + LastErrorIdentifier, + initializeToDefault: false)); + } + + if (!statements.GuaranteedUnmarshal.IsEmpty) + { + setupStatements.Add(MarshallerHelpers.Declare(PredefinedType(Token(SyntaxKind.BoolKeyword)), InvokeSucceededIdentifier, initializeToDefault: true)); + } + + setupStatements.AddRange(declarations.Initializations); + setupStatements.AddRange(declarations.Variables); + setupStatements.AddRange(statements.Setup); + + var tryStatements = new List(); + tryStatements.AddRange(statements.Marshal); + + + BlockSyntax fixedBlock = Block(statements.PinnedMarshal); + if (_setLastError) + { + StatementSyntax clearLastError = MarshallerHelpers.CreateClearLastSystemErrorStatement(SuccessErrorCode); + + StatementSyntax getLastError = MarshallerHelpers.CreateGetLastSystemErrorStatement(LastErrorIdentifier); + + fixedBlock = fixedBlock.AddStatements(clearLastError, statements.InvokeStatement, getLastError); + } + else + { + fixedBlock = fixedBlock.AddStatements(statements.InvokeStatement); + } + tryStatements.Add(statements.Pin.CastArray().NestFixedStatements(fixedBlock)); + + // = true; + if (!statements.GuaranteedUnmarshal.IsEmpty) + { + tryStatements.Add(ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, + IdentifierName(InvokeSucceededIdentifier), + LiteralExpression(SyntaxKind.TrueLiteralExpression)))); + } + + tryStatements.AddRange(statements.NotifyForSuccessfulInvoke); + tryStatements.AddRange(statements.Unmarshal); + + List allStatements = setupStatements; + List finallyStatements = new List(); + if (!statements.GuaranteedUnmarshal.IsEmpty) + { + finallyStatements.Add(IfStatement(IdentifierName(InvokeSucceededIdentifier), Block(statements.GuaranteedUnmarshal))); + } + + finallyStatements.AddRange(statements.Cleanup); + if (finallyStatements.Count > 0) + { + // Add try-finally block if there are any statements in the finally block + allStatements.Add( + TryStatement(Block(tryStatements), default, FinallyClause(Block(finallyStatements)))); + } + else + { + allStatements.AddRange(tryStatements); + } + + if (_setLastError) + { + // Marshal.SetLastPInvokeError(); + allStatements.Add(MarshallerHelpers.CreateSetLastPInvokeErrorStatement(LastErrorIdentifier)); + } + + // Return + if (!_marshallers.IsManagedVoidReturn) + allStatements.Add(ReturnStatement(IdentifierName(_context.GetIdentifiers(_marshallers.ManagedReturnMarshaller.TypeInfo).managed))); + + return Block(allStatements); + } + + private ExpressionSyntax CreateFunctionPointerExpression( + ExpressionSyntax untypedFunctionPointerExpression, + ImmutableArray callConv) + { + List functionPointerParameters = new(); + var (paramList, retType, _) = _marshallers.GenerateTargetMethodSignatureData(); + functionPointerParameters.AddRange(paramList.Parameters.Select(p => FunctionPointerParameter(p.Type))); + functionPointerParameters.Add(FunctionPointerParameter(retType)); + + // ((delegate* unmanaged<...>)) + return ParenthesizedExpression(CastExpression( + FunctionPointerType( + FunctionPointerCallingConvention(Token(SyntaxKind.UnmanagedKeyword), callConv.IsEmpty ? null : FunctionPointerUnmanagedCallingConventionList(SeparatedList(callConv))), + FunctionPointerParameterList(SeparatedList(functionPointerParameters))), + untypedFunctionPointerExpression)); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Microsoft.Interop.ComInterfaceGenerator.props b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Microsoft.Interop.ComInterfaceGenerator.props new file mode 100644 index 0000000000000..359b965f88380 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Microsoft.Interop.ComInterfaceGenerator.props @@ -0,0 +1,9 @@ + + + + + diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/Strings.resx b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/Strings.resx new file mode 100644 index 0000000000000..8bacf040d57ab --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/Strings.resx @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Source-generated P/Invokes will ignore any configuration that is not supported. + + + The '{0}' configuration is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + + + The specified marshalling configuration is not supported by source-generated P/Invokes. {0}. + + + The specified '{0}' configuration for parameter '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + + + The specified '{0}' configuration for the return value of method '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + + + The specified value '{0}' for '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + + + Specified configuration is not supported by source-generated P/Invokes. + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid. + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' on method '{0}' is invalid. {1} + {1} is a message containing additional details about what is not valid + + + 'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'. + + + 'StringMarshalling' should be set to 'StringMarshalling.Custom' when 'StringMarshallingCustomType' is specified. + + + For types that are not supported by source-generated P/Invokes, the resulting P/Invoke will rely on the underlying runtime to marshal the specified type. + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter '{1}'. + + + {0} The generated source will not handle marshalling of parameter '{1}'. + {0} is a message containing additional details about what is not supported +{1} is the name of the parameter + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of the return value of method '{1}'. + + + {0} The generated source will not handle marshalling of the return value of method '{1}'. + {0} is a message containing additional details about what is not supported +{1} is the name of the method + + + Specified type is not supported by source-generated P/Invokes + + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + + + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + + + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + + + Invalid 'LibraryImportAttribute' usage + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.cs.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.cs.xlf new file mode 100644 index 0000000000000..a96bb0372aaf0 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.cs.xlf @@ -0,0 +1,114 @@ + + + + + + Source-generated P/Invokes will ignore any configuration that is not supported. + Zdrojem generovaná volání P/Invokes budou ignorovat všechny nepodporované konfigurace. + + + + The '{0}' configuration is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + Konfiguraci {0} nepodporují zdrojem generovaná volání P/Invokes. Pokud je určená konfigurace povinná, použijte místo ní normální DllImport. + + + + The specified marshalling configuration is not supported by source-generated P/Invokes. {0}. + Určenou konfiguraci zařazování nepodporují zdrojem generovaná volání P/Invokes. {0}. + + + + The specified '{0}' configuration for parameter '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + Určená konfigurace {0} pro parametr {1} není podporována voláním P/Invokes. Pokud je určená konfigurace povinná, použijte místo ní normální DllImport. + + + + The specified '{0}' configuration for the return value of method '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + Určenou konfiguraci {0} návratové hodnoty metody {1} nepodporují zdrojem generovaná volání P/Invokes. Pokud je určená konfigurace povinná, použijte místo ní normální Dllimport. + + + + The specified value '{0}' for '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + Určená hodnota {0} pro {1} se nepodporuje u zdrojem generovaných volání P/Invokes. Pokud je určená konfigurace povinná, použijte místo ní normální Dllimport. + + + + Specified configuration is not supported by source-generated P/Invokes. + Určenou konfiguraci nepodporují zdrojem generovaná volání P/Invokes. + + + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + + + + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + + + + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + + + + Invalid 'LibraryImportAttribute' usage + Invalid 'LibraryImportAttribute' usage + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid. + Konfigurace StringMarshalling a StringMarshallingCustomType je neplatná. + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' on method '{0}' is invalid. {1} + Konfigurace StringMarshalling a StringMarshallingCustomType u metody {0} je neplatná. {1} + {1} is a message containing additional details about what is not valid + + + 'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'. + StringMarshallingCustomType musí být určený, pokud je StringMarshalling nastavený na StringMarshalling.Custom. + + + + 'StringMarshalling' should be set to 'StringMarshalling.Custom' when 'StringMarshallingCustomType' is specified. + StringMarshalling by měl být nastavený na StringMarshalling.Custom, když je pokud je určený StringMarshallingCustomType. + + + + For types that are not supported by source-generated P/Invokes, the resulting P/Invoke will rely on the underlying runtime to marshal the specified type. + U typů, které nejsou podporovány zdrojem generovanými voláními P/Invoke, bude výsledné volání P/Invoke záviset na podkladovém modulu runtime, aby určený typ zařadil. + + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter '{1}'. + Typ {0} nepodporují zdrojem generovaná volání P/Invokes. Vygenerovaný zdroj nebude zpracovávat zařazování parametru {1}. + + + + {0} The generated source will not handle marshalling of parameter '{1}'. + {0} Generovaný zdroj nebude zpracovávat zařazování parametru {1}. + {0} is a message containing additional details about what is not supported +{1} is the name of the parameter + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of the return value of method '{1}'. + Typ {0} nepodporují zdrojem generovaná volání P/Invokes. Vygenerovaný zdroj nebude zpracovávat zařazování návratové hodnoty metody {1}. + + + + {0} The generated source will not handle marshalling of the return value of method '{1}'. + {0} Generovaný zdroj nebude zpracovávat zařazování návratové hodnoty metody {1}. + {0} is a message containing additional details about what is not supported +{1} is the name of the method + + + Specified type is not supported by source-generated P/Invokes + Určený typ nepodporují zdrojem generovaná volání P/Invokes. + + + + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.de.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.de.xlf new file mode 100644 index 0000000000000..bf465c7641a91 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.de.xlf @@ -0,0 +1,114 @@ + + + + + + Source-generated P/Invokes will ignore any configuration that is not supported. + Quellgenerierte P/Invokes ignorieren alle Konfigurationen, die nicht unterstützt werden. + + + + The '{0}' configuration is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + Die Konfiguration \"{0}\" wird von quellgenerierten P/Invokes nicht unterstützt. Wenn die angegebene Konfiguration erforderlich ist, verwenden Sie stattdessen einen regulären DllImport. + + + + The specified marshalling configuration is not supported by source-generated P/Invokes. {0}. + Die angegebene Marshallingkonfiguration wird von quellgenerierten P/Invokes nicht unterstützt. {0}. + + + + The specified '{0}' configuration for parameter '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + Die angegebene Konfiguration \"{0}\" für den Parameter \"{1}\" wird von quellgenerierten P/Invokes nicht unterstützt. Wenn die angegebene Konfiguration erforderlich ist, verwenden Sie stattdessen einen regulären \"DllImport\". + + + + The specified '{0}' configuration for the return value of method '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + Die angegebene Konfiguration \"{0}\" für den Rückgabewert der Methode \"{1}\" wird von quellgenerierten P/Invokes nicht unterstützt. Wenn die angegebene Konfiguration erforderlich ist, verwenden Sie stattdessen einen regulären DllImport. + + + + The specified value '{0}' for '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + Der angegebene Wert \"{0}\" für \"{1}\" wird von quellgenerierten P/Invokes nicht unterstützt. Wenn die angegebene Konfiguration erforderlich ist, verwenden Sie stattdessen einen regulären \"DllImport\". + + + + Specified configuration is not supported by source-generated P/Invokes. + Die angegebene Konfiguration wird von quellgenerierten P/Invokes nicht unterstützt. + + + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + + + + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + + + + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + + + + Invalid 'LibraryImportAttribute' usage + Invalid 'LibraryImportAttribute' usage + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid. + Die Konfiguration von \"StringMarshalling\" und \"StringMarshallingCustomType\" ist ungültig. + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' on method '{0}' is invalid. {1} + Die Konfiguration von \"StringMarshalling\" und \"StringMarshallingCustomType\" für die Methode \"{0}\" ist ungültig. {1} + {1} is a message containing additional details about what is not valid + + + 'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'. + \"StringMarshallingCustomType\" muss angegeben werden, wenn \"StringMarshalling\" auf \"StringMarshalling.Custom\" festgelegt ist. + + + + 'StringMarshalling' should be set to 'StringMarshalling.Custom' when 'StringMarshallingCustomType' is specified. + \"StringMarshalling\" muss auf \"StringMarshalling.Custom\" festgelegt werden, wenn \"StringMarshallingCustomType\" angegeben ist. + + + + For types that are not supported by source-generated P/Invokes, the resulting P/Invoke will rely on the underlying runtime to marshal the specified type. + Bei Typen, die von dquellgenerierten P/Invokes nicht unterstützt werden, basiert der resultierende P/Invoke auf der zugrunde liegenden Laufzeit, um den angegebenen Typ zu marshallen. + + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter '{1}'. + Der Typ \"{0}\" wird von vom Quellcode generierten P/Invokes nicht unterstützt. Die generierte Quelle verarbeitet das Marshalling des Parameters \"{1}\" nicht. + + + + {0} The generated source will not handle marshalling of parameter '{1}'. + {0} Die generierte Quelle verarbeitet das Marshalling des Parameters \"{1}\" nicht. + {0} is a message containing additional details about what is not supported +{1} is the name of the parameter + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of the return value of method '{1}'. + Der Typ \"{0}\" wird von vom Quellcode generierten P/Invokes nicht unterstützt. Die generierte Quelle verarbeitet das Marshalling des Rückgabewerts der Methode \"{1}\" nicht. + + + + {0} The generated source will not handle marshalling of the return value of method '{1}'. + {0} Die generierte Quelle verarbeitet das Marshalling des Rückgabewerts der Methode \"{1}\" nicht. + {0} is a message containing additional details about what is not supported +{1} is the name of the method + + + Specified type is not supported by source-generated P/Invokes + Der angegebene Typ wird von quellgenerierten P/Invokes nicht unterstützt. + + + + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.es.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.es.xlf new file mode 100644 index 0000000000000..3f3ce2505f8a8 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.es.xlf @@ -0,0 +1,114 @@ + + + + + + Source-generated P/Invokes will ignore any configuration that is not supported. + Los P/Invoke de un generador de código fuente omitirán cualquier configuración que no esté admitida. + + + + The '{0}' configuration is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + La configuración de “{0}” no está admitida por P/Invokes de un generador de código fuente. Si se requiere la configuración, use un “DllImport” normal en su lugar. + + + + The specified marshalling configuration is not supported by source-generated P/Invokes. {0}. + La configuración de serialización especificada no está admitida por P/Invokes de un generador de código fuente. {0}. + + + + The specified '{0}' configuration for parameter '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + La configuración de “{0}” especificada para el parámetro “{1}” no es compatible con P/Invokes de un generador de código fuente. Si se requiere la configuración especificada, use un “DllImport” normal en su lugar. + + + + The specified '{0}' configuration for the return value of method '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + La configuración de “{0}” especificada para el valor devuelto del método “{1}” no es compatible con P/Invokes generados por origen. Si se requiere la configuración especificada, use un “DllImport” normal en su lugar. + + + + The specified value '{0}' for '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + El valor especificado de “{0}” para “{1}” no es compatible con P/Invokes de un generador de código fuente. Si se requiere la configuración especificada, use un “DllImport” normal en su lugar. + + + + Specified configuration is not supported by source-generated P/Invokes. + La configuración especificada no está admitida por P/Invokes de un generador de código fuente. + + + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + + + + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + + + + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + + + + Invalid 'LibraryImportAttribute' usage + Invalid 'LibraryImportAttribute' usage + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid. + La configuración de “StringMarshalling” y “StringMarshallingCustomType” no es válida. + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' on method '{0}' is invalid. {1} + La configuración de “StringMarshalling” y “StringMarshallingCustomType” en el método “{0}” no es válida. {1} + {1} is a message containing additional details about what is not valid + + + 'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'. + Se debe especificar “StringMarshallingCustomType” cuando “StringMarshalling” esté establecido en “StringMarshalling.Custom”. + + + + 'StringMarshalling' should be set to 'StringMarshalling.Custom' when 'StringMarshallingCustomType' is specified. + “StringMarshalling” debe establecerse en “StringMarshalling.Custom” cuando “StringMarshallingCustomType” esté especificado. + + + + For types that are not supported by source-generated P/Invokes, the resulting P/Invoke will rely on the underlying runtime to marshal the specified type. + Para los tipos que no son compatibles con P/Invokes de un generador de código fuente, el P/Invoke resultante se basará en el entorno de ejecución subyacente para serializar las referencias del tipo especificado. + + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter '{1}'. + El tipo “{0}” no es compatible con P/Invokes de un generador de código fuente. El código fuente generado no controlará la serialización del parámetro “{1}”. + + + + {0} The generated source will not handle marshalling of parameter '{1}'. + {0} El origen generado no controlará la serialización del parámetro “{1}”. + {0} is a message containing additional details about what is not supported +{1} is the name of the parameter + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of the return value of method '{1}'. + El tipo “{0}” no es compatible con P/Invokes de un generador de código fuente. El código fuente generado no controlará la serialización del valor devuelto del método “{1}”. + + + + {0} The generated source will not handle marshalling of the return value of method '{1}'. + {0} El código fuente generado no controlará la serialización del valor devuelto del método “{1}”. + {0} is a message containing additional details about what is not supported +{1} is the name of the method + + + Specified type is not supported by source-generated P/Invokes + El tipo especificado no está admitido por P/Invokes de un generador de código fuente + + + + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.fr.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.fr.xlf new file mode 100644 index 0000000000000..7a10a0812a863 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.fr.xlf @@ -0,0 +1,114 @@ + + + + + + Source-generated P/Invokes will ignore any configuration that is not supported. + Les P/Invokes générés par la source ignorent toute configuration qui n’est pas prise en charge. + + + + The '{0}' configuration is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + La configuration de « {0} » n’est pas prise en charge par les P/Invok générés par la source. Si la configuration spécifiée est requise, utilisez plutôt un « DllImport » normal. + + + + The specified marshalling configuration is not supported by source-generated P/Invokes. {0}. + La configuration de marshaling spécifiée n’est pas prise en charge par les P/Invokes générés par la source. {0}. + + + + The specified '{0}' configuration for parameter '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + La configuration de « {0} » spécifiée pour le paramètre « {1} » n’est pas prise en charge par les P/Invok générés par la source. Si la configuration spécifiée est requise, utilisez plutôt un « DllImport » normal. + + + + The specified '{0}' configuration for the return value of method '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + La configuration de « {0} » spécifiée pour la valeur renvoyée de la méthode « {1} » n’est pas prise en charge par les P/Invok générés par la source. Si la configuration spécifiée est requise, utilisez plutôt un « DllImport » normal. + + + + The specified value '{0}' for '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + La valeur de « {0} » spécifiée pour « {1} » n’est pas prise en charge par les P/Invok générés par la source. Si la configuration spécifiée est requise, utilisez plutôt un « DllImport » normal. + + + + Specified configuration is not supported by source-generated P/Invokes. + La configuration spécifiée n’est pas prise en charge par les P/Invokes générés par la source. + + + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + + + + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + + + + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + + + + Invalid 'LibraryImportAttribute' usage + Invalid 'LibraryImportAttribute' usage + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid. + La configuration de « StringMarshalling » et de « StringMarshallingCustomType » n’est pas valide. + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' on method '{0}' is invalid. {1} + La configuration de « StringMarshalling » et de « StringMarshallingCustomType » n’est sur la méthode « {0} » pas valide. {1} + {1} is a message containing additional details about what is not valid + + + 'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'. + « StringMarshallingCustomType » doit être spécifié quand « StringMarshalling » a la valeur « StringMarshalling.Custom ». + + + + 'StringMarshalling' should be set to 'StringMarshalling.Custom' when 'StringMarshallingCustomType' is specified. + « StringMarshalling » doit être défini sur « StringMarshalling.Custom » quand « StringMarshallingCustomType » est spécifié. + + + + For types that are not supported by source-generated P/Invokes, the resulting P/Invoke will rely on the underlying runtime to marshal the specified type. + Pour les types qui ne sont pas pris en charge par les P/Invok générés par la source, le P/Invoke résultant se base sur le runtime sous-jacent pour marshaler le type spécifié. + + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter '{1}'. + Le type « {0} » n’est pas pris en charge par les P/Invokes générés par la source. La source générée ne gère pas le marshaling du paramètre « {1} ». + + + + {0} The generated source will not handle marshalling of parameter '{1}'. + {0} La source générée ne gère pas le marshaling du paramètre « {1} ». + {0} is a message containing additional details about what is not supported +{1} is the name of the parameter + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of the return value of method '{1}'. + Le type « {0} » n’est pas pris en charge par les P/Invokes générés par la source. La source générée ne gère pas le marshaling de la valeur de retour de la méthode « {1} ». + + + + {0} The generated source will not handle marshalling of the return value of method '{1}'. + {0} La source générée ne gère pas le marshaling de la valeur de retour de la méthode « {1} ». + {0} is a message containing additional details about what is not supported +{1} is the name of the method + + + Specified type is not supported by source-generated P/Invokes + Le type spécifié n’est pas prise en charge par les P/Invokes générés par la source. + + + + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.it.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.it.xlf new file mode 100644 index 0000000000000..be3a16f70670c --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.it.xlf @@ -0,0 +1,114 @@ + + + + + + Source-generated P/Invokes will ignore any configuration that is not supported. + I P/Invoke generati dall'origine ignoreranno qualsiasi configurazione non supportata. + + + + The '{0}' configuration is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + La configurazione '{0}' non è supportata dai P/Invoke generati dall'origine. Se la configurazione specificata è obbligatoria, usare un attributo `DllImport` normale. + + + + The specified marshalling configuration is not supported by source-generated P/Invokes. {0}. + La configurazione di marshalling specificata non è supportata dai P/Invoke generati dall'origine. {0}. + + + + The specified '{0}' configuration for parameter '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + La configurazione '{0}' specificata per il parametro '{1}' non è supportata dai P/Invoke generati dall'origine. Se la configurazione specificata è obbligatoria, usare un attributo `DllImport` normale. + + + + The specified '{0}' configuration for the return value of method '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + La configurazione '{0}' specificata per il valore restituito del metodo '{1}' non è supportata dai P/Invoke generati dall'origine. Se la configurazione specificata è obbligatoria, usare un attributo `DllImport` normale. + + + + The specified value '{0}' for '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + Il valore '{0}' specificato per '{1}' non è supportato dai P/Invoke generati dall'origine. Se la configurazione specificata è obbligatoria, usare un attributo `DllImport` normale. + + + + Specified configuration is not supported by source-generated P/Invokes. + La configurazione specificata non è supportata dai P/Invoke generati dall'origine. + + + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + + + + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + + + + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + + + + Invalid 'LibraryImportAttribute' usage + Invalid 'LibraryImportAttribute' usage + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid. + La configurazione di 'StringMarshalling' e 'StringMarshallingCustomType' non è valida. + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' on method '{0}' is invalid. {1} + La configurazione di 'StringMarshalling' e 'StringMarshallingCustomType' nel metodo '{0}' non è valida. {1} + {1} is a message containing additional details about what is not valid + + + 'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'. + È necessario specificare 'StringMarshallingCustomType' quando 'StringMarshalling' è impostato su 'StringMarshalling.Custom'. + + + + 'StringMarshalling' should be set to 'StringMarshalling.Custom' when 'StringMarshallingCustomType' is specified. + 'StringMarshalling' deve essere impostato su 'StringMarshalling.Custom' quando è specificato 'StringMarshallingCustomType'. + + + + For types that are not supported by source-generated P/Invokes, the resulting P/Invoke will rely on the underlying runtime to marshal the specified type. + Per i tipi non supportati da P/Invoke generati dall'origine, il P/Invoke risultante si baserà sul runtime sottostante per effettuare il marshalling del tipo specificato. + + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter '{1}'. + Il tipo '{0}' non è supportato dai P/Invoke generati dall'origine. L'origine generata non gestirà il marshalling del parametro '{1}'. + + + + {0} The generated source will not handle marshalling of parameter '{1}'. + {0} L'origine generata non gestirà il marshalling del parametro '{1}'. + {0} is a message containing additional details about what is not supported +{1} is the name of the parameter + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of the return value of method '{1}'. + Il tipo '{0}' non è supportato dai P/Invoke generati dall'origine. L'origine generata non gestirà il marshalling del valore restituito del metodo '{1}'. + + + + {0} The generated source will not handle marshalling of the return value of method '{1}'. + {0} L'origine generata non gestirà il marshalling del valore restituito del metodo '{1}'. + {0} is a message containing additional details about what is not supported +{1} is the name of the method + + + Specified type is not supported by source-generated P/Invokes + Il tipo specificato non è supportato dai P/Invoke generati dall'origine + + + + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ja.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ja.xlf new file mode 100644 index 0000000000000..f349a06cba61d --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ja.xlf @@ -0,0 +1,114 @@ + + + + + + Source-generated P/Invokes will ignore any configuration that is not supported. + ソース生成済みの P/Invoke は、サポートされていない構成を無視します。 + + + + The '{0}' configuration is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + '{0}' 構成は、ソース生成済みの P/Invoke ではサポートされていません。指定された構成が必要な場合は、代わりに通常の 'DllImport' を使用します。 + + + + The specified marshalling configuration is not supported by source-generated P/Invokes. {0}. + 指定されたマーシャリング構成は、ソースで生成された P/Invoke ではサポートされていません。{0}。 + + + + The specified '{0}' configuration for parameter '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + パラメーター '{1}' 向けに指定された '{0}' 構成は、ソース生成済みの P/Invoke ではサポートされていません。指定された構成が必要な場合は、代わりに通常の 'DllImport' を使用します。 + + + + The specified '{0}' configuration for the return value of method '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + メソッド '{1}' の戻り値向けに指定された '{0}' 構成は、ソース生成済みの P/Invoke ではサポートされていません。指定された構成が必要な場合は、代わりに通常の 'DllImport' を使用します。 + + + + The specified value '{0}' for '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + '{1}' 向けに指定された値 '{0}' は、ソース生成済みの P/Invoke ではサポートされていません。指定された構成が必要な場合は、代わりに通常の 'DllImport' を使用します。 + + + + Specified configuration is not supported by source-generated P/Invokes. + 指定された構成は、ソースで生成された P/Invoke ではサポートされていません。 + + + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + + + + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + + + + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + + + + Invalid 'LibraryImportAttribute' usage + Invalid 'LibraryImportAttribute' usage + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid. + 'StringMarshalling' と 'StringMarshallingCustomType' の構成が無効です。 + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' on method '{0}' is invalid. {1} + メソッド '{0}' の 'StringMarshalling' と 'StringMarshallingCustomType' の構成が無効です。{1} + {1} is a message containing additional details about what is not valid + + + 'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'. + 'StringMarshalling' が 'StringMarshalling.Custom' に設定されている場合は、'StringMarshallingCustomType' を指定する必要があります。 + + + + 'StringMarshalling' should be set to 'StringMarshalling.Custom' when 'StringMarshallingCustomType' is specified. + 'StringMarshallingCustomType' が指定されている場合、'StringMarshalling' を 'StringMarshalling.Custom' に設定する必要があります。 + + + + For types that are not supported by source-generated P/Invokes, the resulting P/Invoke will rely on the underlying runtime to marshal the specified type. + ソース生成済みの P/Invoke でサポートされていない型である場合、生成された P/Invoke は、基礎となるなるランタイムに依存して、指定された型をマーシャリングします。 + + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter '{1}'. + 型 '{0}' は、ソース生成済みの P/Invoke ではサポートされていません。生成されたソースは、パラメーター '{1}' のマーシャリングを処理しません。 + + + + {0} The generated source will not handle marshalling of parameter '{1}'. + {0} 生成されたソースはパラメーター '{1}' のマーシャリングを処理しません。 + {0} is a message containing additional details about what is not supported +{1} is the name of the parameter + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of the return value of method '{1}'. + 型 '{0}' は、ソース生成済みの P/Invoke ではサポートされていません。生成されたソースは、メソッド '{1}' の戻り値のマーシャリングを処理しません。 + + + + {0} The generated source will not handle marshalling of the return value of method '{1}'. + {0} 生成されたソースは、メソッド '{1}' の戻り値のマーシャリングを処理しません。 + {0} is a message containing additional details about what is not supported +{1} is the name of the method + + + Specified type is not supported by source-generated P/Invokes + 指定された型は、ソースで生成された P/Invoke ではサポートされていません + + + + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ko.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ko.xlf new file mode 100644 index 0000000000000..53bb45e12ef65 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ko.xlf @@ -0,0 +1,114 @@ + + + + + + Source-generated P/Invokes will ignore any configuration that is not supported. + 소스 생성 P/Invoke는 지원되지 않는 구성을 무시합니다. + + + + The '{0}' configuration is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + '{0}' 구성은 소스 생성 P/Invoke에서 지원되지 않습니다. 지정된 구성이 필요한 경우 일반 'DllImport'를 대신 사용하세요. + + + + The specified marshalling configuration is not supported by source-generated P/Invokes. {0}. + 지정된 마샬링 구성은 소스 생성 P/Invoke에서 지원되지 않습니다. {0}. + + + + The specified '{0}' configuration for parameter '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + 매개 변수 '{1}'에 대해 지정된 '{0}' 구성이 소스 생성 P/Invoke에서 지원되지 않습니다. 지정된 구성이 필요한 경우 일반 'DllImport'를 대신 사용하세요. + + + + The specified '{0}' configuration for the return value of method '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + 메서드 '{1}'의 반환 값에 대해 지정된 '{0}' 구성은 소스 생성 P/Invoke에서 지원되지 않습니다. 지정된 구성이 필요한 경우 일반 'DllImport'를 대신 사용하세요. + + + + The specified value '{0}' for '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + '{1}'에 대해 지정된 값 '{0}'은(는) 소스 생성 P/Invoke에서 지원되지 않습니다. 지정된 구성이 필요한 경우 일반 'DllImport'를 대신 사용하세요. + + + + Specified configuration is not supported by source-generated P/Invokes. + 지정된 구성은 소스 생성 P/Invoke에서 지원되지 않습니다. + + + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + + + + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + + + + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + + + + Invalid 'LibraryImportAttribute' usage + Invalid 'LibraryImportAttribute' usage + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid. + 'StringMarshalling' 및 'StringMarshallingCustomType'의 구성이 잘못되었습니다. + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' on method '{0}' is invalid. {1} + '{0}' 메서드의 'StringMarshalling' 및 'StringMarshallingCustomType' 구성이 잘못되었습니다. {1} + {1} is a message containing additional details about what is not valid + + + 'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'. + 'StringMarshalling'이 'StringMarshalling.Custom'으로 설정된 경우 'StringMarshallingCustomType'을 지정해야 합니다. + + + + 'StringMarshalling' should be set to 'StringMarshalling.Custom' when 'StringMarshallingCustomType' is specified. + 'StringMarshallingCustomType'이 지정된 경우 'StringMarshalling'은 'StringMarshalling.Custom'으로 설정되어야 합니다. + + + + For types that are not supported by source-generated P/Invokes, the resulting P/Invoke will rely on the underlying runtime to marshal the specified type. + 소스 생성 P/Invoke에서 지원하지 않는 형식의 경우 결과 P/Invoke는 기본 런타임에 의존하여 지정된 형식을 마샬링합니다. + + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter '{1}'. + 형식 '{0}'은(는) 소스 생성 P/Invoke에서 지원되지 않습니다. 생성된 소스는 '{1}' 매개 변수의 마샬링을 처리하지 않습니다. + + + + {0} The generated source will not handle marshalling of parameter '{1}'. + {0} 생성된 소스는 '{1}' 매개 변수의 마샬링을 처리하지 않습니다. + {0} is a message containing additional details about what is not supported +{1} is the name of the parameter + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of the return value of method '{1}'. + 형식 '{0}'은(는) 소스 생성 P/Invoke에서 지원되지 않습니다. 생성된 소스는 '{1}' 메서드의 반환 값 마샬링을 처리하지 않습니다. + + + + {0} The generated source will not handle marshalling of the return value of method '{1}'. + {0} 생성된 소스는 '{1}' 메서드의 반환 값 마샬링을 처리하지 않습니다. + {0} is a message containing additional details about what is not supported +{1} is the name of the method + + + Specified type is not supported by source-generated P/Invokes + 지정된 형식은 소스 생성 P/Invoke에서 지원되지 않습니다. + + + + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.pl.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.pl.xlf new file mode 100644 index 0000000000000..283a271d108ec --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.pl.xlf @@ -0,0 +1,114 @@ + + + + + + Source-generated P/Invokes will ignore any configuration that is not supported. + Funkcja P/Invokes generowana przez źródło zignoruje każdą nieobsługiwaną konfigurację. + + + + The '{0}' configuration is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + Konfiguracja {0} nie jest obsługiwana przez funkcję P/Invokes generowaną przez źródło. Jeśli określona konfiguracja jest wymagana, użyj zamiast tego zwykłego elementu „DllImport”. + + + + The specified marshalling configuration is not supported by source-generated P/Invokes. {0}. + Określona konfiguracja skierowania nie jest obsługiwana przez funkcję P/Invokes generowaną przez źródło. {0}. + + + + The specified '{0}' configuration for parameter '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + Określona konfiguracja „{0}” dla parametru „{1}” nie jest obsługiwana przez funkcję P/Invokes generowaną przez źródło. Jeśli określona konfiguracja jest wymagana, użyj zamiast tego zwykłego elementu „DllImport”. + + + + The specified '{0}' configuration for the return value of method '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + Określona konfiguracja „{0}” dla wartości zwracanej przez metodę „{1}” nie jest obsługiwana przez funkcję P/Invokes generowaną przez źródło. Jeśli określona konfiguracja jest wymagana, użyj zamiast tego zwykłego elementu „DllImport”. + + + + The specified value '{0}' for '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + Określona wartość „{0}” dla parametru „{1}” nie jest obsługiwana przez funkcję P/Invokes generowaną przez źródło. Jeśli określona konfiguracja jest wymagana, użyj zamiast tego zwykłego elementu „DllImport”. + + + + Specified configuration is not supported by source-generated P/Invokes. + Określona konfiguracja nie jest obsługiwana przez funkcję P/Invokes generowaną przez źródło. + + + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + + + + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + + + + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + + + + Invalid 'LibraryImportAttribute' usage + Invalid 'LibraryImportAttribute' usage + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid. + Konfiguracja elementów „StringMarshalling” i „StringMarshallingCustomType” jest nieprawidłowa. + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' on method '{0}' is invalid. {1} + Konfiguracja elementów „StringMarshalling” i „StringMarshallingCustomType” w metodzie „{0}” jest nieprawidłowa. {1} + {1} is a message containing additional details about what is not valid + + + 'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'. + Element „StringMarshallingCustomType” należy określić, gdy element „StringMarshalling” ma wartość „StringMarshalling.Custom”. + + + + 'StringMarshalling' should be set to 'StringMarshalling.Custom' when 'StringMarshallingCustomType' is specified. + Element „StringMarshalling” należy ustawić na wartość „StringMarshalling.Custom”, gdy określono element „StringMarshallingCustomType”. + + + + For types that are not supported by source-generated P/Invokes, the resulting P/Invoke will rely on the underlying runtime to marshal the specified type. + W przypadku typów, które nie są obsługiwane przez funkcję P/Invokes generowaną przez źródło, wynikowa funkcja P/Invoke będzie polegać na bazowym środowisku uruchomieniowym, aby skierować określony typ. + + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter '{1}'. + Typ „{0}” nie jest obsługiwany przez funkcję P/Invokes generowaną przez źródło. Wygenerowane źródło nie obsługuje skierowania parametru „{1}”. + + + + {0} The generated source will not handle marshalling of parameter '{1}'. + {0} Wygenerowane źródło nie obsługuje skierowania parametru „{1}”. + {0} is a message containing additional details about what is not supported +{1} is the name of the parameter + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of the return value of method '{1}'. + Typ „{0}” nie jest obsługiwany przez funkcję P/Invokes generowaną przez źródło. Wygenerowane źródło nie obsługuje skierowania wartości zwracanej przez metodę „{1}”. + + + + {0} The generated source will not handle marshalling of the return value of method '{1}'. + {0}Wygenerowane źródło nie obsługuje skierowania wartości zwracanej przez metodę „{1}”. + {0} is a message containing additional details about what is not supported +{1} is the name of the method + + + Specified type is not supported by source-generated P/Invokes + Określony typ nie jest obsługiwany przez funkcję P/Invokes generowaną przez źródło + + + + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.pt-BR.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.pt-BR.xlf new file mode 100644 index 0000000000000..8fecda2e4234a --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.pt-BR.xlf @@ -0,0 +1,114 @@ + + + + + + Source-generated P/Invokes will ignore any configuration that is not supported. + P/Invokes gerados pela origem ignorarão qualquer configuração sem suporte. + + + + The '{0}' configuration is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + A configuração '{0}' não é suportada por P/Invokes gerados pela origem. Se a configuração especificada for necessária, use um 'DllImport' regular. + + + + The specified marshalling configuration is not supported by source-generated P/Invokes. {0}. + Não há suporte para a configuração de marshaling especificada por P/Invokes gerados pela origem. {0}. + + + + The specified '{0}' configuration for parameter '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + A configuração '{0}' especificada para o parâmetro '{1}' não é suportada por P/Invokes gerados pela origem. Se a configuração especificada for necessária, use um 'DllImport' regular. + + + + The specified '{0}' configuration for the return value of method '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + A configuração '{0}' especificada para o valor retornado do método '{1}' não é suportada por P/Invokes gerados pela origem. Se a configuração especificada for necessária, use um 'DllImport' regular. + + + + The specified value '{0}' for '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + O valor '{0}' especificado para '{1}' não é suportada por P/Invokes gerados pela origem. Se a configuração especificada for necessária, use um 'DllImport' regular. + + + + Specified configuration is not supported by source-generated P/Invokes. + A configuração especificada não tem suporte de P/Invokes gerados pela origem. + + + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + + + + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + + + + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + + + + Invalid 'LibraryImportAttribute' usage + Invalid 'LibraryImportAttribute' usage + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid. + A configuração de 'StringMarshalling' e 'StringMarshallingCustomType' é inválida. + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' on method '{0}' is invalid. {1} + A configuração de 'StringMarshalling' e 'StringMarshallingCustomType' no método '{0}' é inválida. {1} + {1} is a message containing additional details about what is not valid + + + 'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'. + 'StringMarshallingCustomType' deve ser especificado quando 'StringMarshalling' está definido como 'StringMarshalling.Custom'. + + + + 'StringMarshalling' should be set to 'StringMarshalling.Custom' when 'StringMarshallingCustomType' is specified. + 'StringMarshalling' deve ser definido como 'StringMarshalling.Custom' quando 'StringMarshallingCustomType' for especificado. + + + + For types that are not supported by source-generated P/Invokes, the resulting P/Invoke will rely on the underlying runtime to marshal the specified type. + Para tipos sem suporte por P/Invokes gerados pela origem, o P/Invoke resultante dependerá do tempo de execução subjacente para realizar marshaling no tipo especificado. + + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter '{1}'. + O tipo '{0}' não é suportado por P/Invokes gerados pela origem. A origem gerada não manipulará o marshalling do parâmetro '{1}'. + + + + {0} The generated source will not handle marshalling of parameter '{1}'. + {0} A origem gerada não manipulará o marshalling do parâmetro '{1}'. + {0} is a message containing additional details about what is not supported +{1} is the name of the parameter + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of the return value of method '{1}'. + O tipo '{0}' não é suportado por P/Invokes gerados pela origem. A origem gerada não tratará marshaling do valor de retorno do método '{1}'. + + + + {0} The generated source will not handle marshalling of the return value of method '{1}'. + {0} A origem gerada não manipulará o marshalling do valor retornado do método '{1}'. + {0} is a message containing additional details about what is not supported +{1} is the name of the method + + + Specified type is not supported by source-generated P/Invokes + O tipo especificado não tem suporte de P/Invokes gerados pela origem. + + + + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ru.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ru.xlf new file mode 100644 index 0000000000000..9503e52e57f52 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ru.xlf @@ -0,0 +1,114 @@ + + + + + + Source-generated P/Invokes will ignore any configuration that is not supported. + P/Invoke с созданием источника будут игнорировать все неподдерживаемые конфигурации. + + + + The '{0}' configuration is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + Конфигурация \"{0}\" не поддерживается в P/Invoke с созданием источника. Если указанная конфигурация обязательна, используйте обычный метод \"DllImport\". + + + + The specified marshalling configuration is not supported by source-generated P/Invokes. {0}. + Указанная конфигурация маршализации не поддерживается в P/Invoke с созданием источника. {0}. + + + + The specified '{0}' configuration for parameter '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + Указанная конфигурация \"{0}\" для параметра \"{1}\" не поддерживается в P/Invoke с созданием источника. Если указанная конфигурация обязательна, используйте обычный метод \"DllImport\". + + + + The specified '{0}' configuration for the return value of method '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + Указанная конфигурация \"{0}\" для возвращаемого значения метода \"{1}\" не поддерживается в P/Invoke с созданием источника. Если указанная конфигурация обязательна, используйте обычный метод \"DllImport\". + + + + The specified value '{0}' for '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + Указанное значение “{0}” для “{1}” не поддерживается в P/Invoke с созданием источника. Если указанная конфигурация обязательна, используйте обычный метод “DllImport”. + + + + Specified configuration is not supported by source-generated P/Invokes. + Указанная конфигурация не поддерживается в P/Invoke с созданием источника. + + + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + + + + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + + + + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + + + + Invalid 'LibraryImportAttribute' usage + Invalid 'LibraryImportAttribute' usage + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid. + Конфигурация \"StringMarshalling\" и \"StringMarshallingCustomType\" недопустима. + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' on method '{0}' is invalid. {1} + Конфигурация \"StringMarshalling\" и \"StringMarshallingCustomType\" в методе \"{0}\" недопустима. {1} + {1} is a message containing additional details about what is not valid + + + 'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'. + Если для \"StringMarshalling\" задано значение \"StringMarshalling.Custom\", необходимо указать \"StringMarshallingCustomType\". + + + + 'StringMarshalling' should be set to 'StringMarshalling.Custom' when 'StringMarshallingCustomType' is specified. + Если указано \"StringMarshallingCustomType\", для \"StringMarshalling\" следует задать значение \"StringMarshalling.Custom\". + + + + For types that are not supported by source-generated P/Invokes, the resulting P/Invoke will rely on the underlying runtime to marshal the specified type. + Для типов, которые не поддерживаются в P/Invoke с созданием источника, в полученном P/Invoke для маршализации указанного типа будет использоваться среда выполнения. + + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter '{1}'. + Тип \"{0}\" не поддерживается в P/Invoke с созданием источника. Созданный источник не будет обрабатывать маршализацию параметра \"{1}\". + + + + {0} The generated source will not handle marshalling of parameter '{1}'. + {0} Созданный источник не будет обрабатывать маршализацию параметра \"{1}\". + {0} is a message containing additional details about what is not supported +{1} is the name of the parameter + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of the return value of method '{1}'. + Тип \"{0}\" не поддерживается в P/Invoke с созданием источника. Созданный источник не будет обрабатывать маршализацию возвращаемого значения метода \"{1}\". + + + + {0} The generated source will not handle marshalling of the return value of method '{1}'. + {0} Созданный источник не будет обрабатывать маршализацию возвращаемого значения метода \"{1}\". + {0} is a message containing additional details about what is not supported +{1} is the name of the method + + + Specified type is not supported by source-generated P/Invokes + Указанный тип не поддерживается в P/Invoke с созданием источника. + + + + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.tr.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.tr.xlf new file mode 100644 index 0000000000000..305afacff2976 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.tr.xlf @@ -0,0 +1,114 @@ + + + + + + Source-generated P/Invokes will ignore any configuration that is not supported. + Kaynak tarafından oluşturulan P/Invokes desteklenmeyen yapılandırmaları yok sayar. + + + + The '{0}' configuration is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + '{0}' yapılandırması, kaynak tarafından oluşturulan P/Invokes tarafından desteklenmiyor. Belirtilen yapılandırma gerekli ise, bunun yerine normal bir 'DllImport' kullanın. + + + + The specified marshalling configuration is not supported by source-generated P/Invokes. {0}. + Belirtilen sıralama yapılandırması, kaynak tarafından oluşturulan P/Invokes tarafından desteklenmiyor. {0}. + + + + The specified '{0}' configuration for parameter '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + '{1}' parametresi için belirtilen '{0}' yapılandırması, kaynak tarafından oluşturulan P/Invokes tarafından desteklenmiyor. Belirtilen yapılandırma gerekli ise, bunun yerine normal bir 'DllImport' kullanın. + + + + The specified '{0}' configuration for the return value of method '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + '{1}' metodunun dönüş değeri için belirtilen '{0}' yapılandırması, kaynak tarafından oluşturulan P/Invokes tarafından desteklenmiyor. Belirtilen yapılandırma gerekli ise, bunun yerine normal bir 'DllImport' kullanın. + + + + The specified value '{0}' for '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + '{1}' için belirtilen '{0}' değeri, kaynak tarafından oluşturulan P/Invokes tarafından desteklenmiyor. Belirtilen yapılandırma gerekli ise, bunun yerine normal bir 'DllImport' kullanın. + + + + Specified configuration is not supported by source-generated P/Invokes. + Belirtilen yapılandırma, kaynak tarafından oluşturulan P/Invokes tarafından desteklenmiyor. + + + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + + + + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + + + + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + + + + Invalid 'LibraryImportAttribute' usage + Invalid 'LibraryImportAttribute' usage + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid. + 'StringMarshalling' ve 'StringMarshallingCustomType' yapılandırması geçersiz. + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' on method '{0}' is invalid. {1} + '{0}' metodundaki 'StringMarshalling' ve 'StringMarshallingCustomType' yapılandırması geçersiz. {1} + {1} is a message containing additional details about what is not valid + + + 'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'. + 'StringMarshalling' 'StringMarshalling.Custom' olarak ayarlandığında 'StringMarshallingCustomType' belirtilmelidir. + + + + 'StringMarshalling' should be set to 'StringMarshalling.Custom' when 'StringMarshallingCustomType' is specified. + 'StringMarshallingCustomType' belirtilirken 'StringMarshalling', 'StringMarshalling.Custom' olarak ayarlanmalıdır. + + + + For types that are not supported by source-generated P/Invokes, the resulting P/Invoke will rely on the underlying runtime to marshal the specified type. + Kaynak tarafından oluşturulan P/Invokes tarafından desteklenmeyen türler için, elde edilen P/Invoke, belirtilen türü sıralamak için temel alınan çalışma zamanını kullanır. + + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter '{1}'. + '{0}' türü, kaynak tarafından oluşturulan P/Invokes tarafından desteklenmiyor. Oluşturulan kaynak, '{1}' parametresinin sıralamasını işlemez. + + + + {0} The generated source will not handle marshalling of parameter '{1}'. + {0} Oluşturulan kaynak '{1}' parametresinin sıralamasını işlemez. + {0} is a message containing additional details about what is not supported +{1} is the name of the parameter + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of the return value of method '{1}'. + '{0}' türü, kaynak tarafından oluşturulan P/Invokes tarafından desteklenmiyor. Oluşturulan kaynak, '{1}' metodunun dönüş değerinin sıralamasını işlemez. + + + + {0} The generated source will not handle marshalling of the return value of method '{1}'. + {0} Oluşturulan kaynak, '{1}' metodunun dönüş değerinin sıralamasını işlemez. + {0} is a message containing additional details about what is not supported +{1} is the name of the method + + + Specified type is not supported by source-generated P/Invokes + Belirtilen tür, kaynak tarafından oluşturulan P/Invokes tarafından desteklenmiyor + + + + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.zh-Hans.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.zh-Hans.xlf new file mode 100644 index 0000000000000..bf58dc9b6290a --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.zh-Hans.xlf @@ -0,0 +1,114 @@ + + + + + + Source-generated P/Invokes will ignore any configuration that is not supported. + 源生成的 P/Invoke 将忽略任何不受支持的配置。 + + + + The '{0}' configuration is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + 源生成的 P/Invoke 不支持“{0}”配置。如果需要指定的配置,请改用常规的 “DllImport”。 + + + + The specified marshalling configuration is not supported by source-generated P/Invokes. {0}. + 源生成的 P/Invoke 不支持指定的封送配置。{0}。 + + + + The specified '{0}' configuration for parameter '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + 源生成的 P/Invoke 不支持为参数“{1}”指定的“{0}”配置。如果需要指定的配置,请改用常规的 `DllImport`。 + + + + The specified '{0}' configuration for the return value of method '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + 源生成的 P/Invoke 不支持为方法“{1}”的返回值指定的“{0}”配置。如果需要指定的配置,请改用常规的 “DllImport”。 + + + + The specified value '{0}' for '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + 源生成的 P/Invoke 不支持为“{1}”指定的值“{0}”。如果需要指定的配置,请改用常规的 “DllImport”。 + + + + Specified configuration is not supported by source-generated P/Invokes. + 源生成的 P/Invoke 不支持指定的配置。 + + + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + + + + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + + + + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + + + + Invalid 'LibraryImportAttribute' usage + Invalid 'LibraryImportAttribute' usage + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid. + “StringMarshalling” 和 “StringMarshallingCustomType” 的配置无效。 + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' on method '{0}' is invalid. {1} + 方法“{0}”上的 “StringMarshalling” 和 “StringMarshallingCustomType” 的配置无效。{1} + {1} is a message containing additional details about what is not valid + + + 'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'. + 在 “StringMarshalling” 设置为 “StringMarshalling.Custom” 时,必须指定 “StringMarshallingCustomType”。 + + + + 'StringMarshalling' should be set to 'StringMarshalling.Custom' when 'StringMarshallingCustomType' is specified. + 在指定 “StringMarshallingCustomType” 时,应将 “StringMarshalling” 设置为 “StringMarshalling.Custom”。 + + + + For types that are not supported by source-generated P/Invokes, the resulting P/Invoke will rely on the underlying runtime to marshal the specified type. + 对于源生成的 P/Invoke 不支持的类型,生成的 P/Invoke 将依赖基础运行时来封送指定的类型。 + + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter '{1}'. + 源生成的 P/Invoke 不支持“{0}”类型。生成的源将不处理参数“{1}”的封送。 + + + + {0} The generated source will not handle marshalling of parameter '{1}'. + {0} 生成的源将不处理参数“{1}”的封送。 + {0} is a message containing additional details about what is not supported +{1} is the name of the parameter + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of the return value of method '{1}'. + 源生成的 P/Invoke 不支持“{0}”类型。生成的源将不处理方法“{1}”的返回值的封送。 + + + + {0} The generated source will not handle marshalling of the return value of method '{1}'. + {0} 生成的源将不处理方法“{1}”的返回值的封送。 + {0} is a message containing additional details about what is not supported +{1} is the name of the method + + + Specified type is not supported by source-generated P/Invokes + 源生成的 P/Invoke 不支持指定的类型 + + + + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.zh-Hant.xlf b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.zh-Hant.xlf new file mode 100644 index 0000000000000..9060dc388da01 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.zh-Hant.xlf @@ -0,0 +1,114 @@ + + + + + + Source-generated P/Invokes will ignore any configuration that is not supported. + 来源產生的 P/Invokes 將會忽略任何不支援的設定。 + + + + The '{0}' configuration is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + 来源產生的 P/Invokes 不支援為'{0}'設定。如果需要指定的設定,請改用一般 'DllImport'。 + + + + The specified marshalling configuration is not supported by source-generated P/Invokes. {0}. + 来源產生的 P/Invokes 不支援指定的排列設定。{0}。 + + + + The specified '{0}' configuration for parameter '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + 来源產生的 P/Invokes 不支援为参數 '{0}' 指定的'{1}'設定。如果需要指定的設定,請改用一般 'DllImport'。 + + + + The specified '{0}' configuration for the return value of method '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + 来源產生的 P/Invokes 不支援為方法 '{0}' 的傳回值指定的 '{1}' 設定。如果需要指定的設定,請改用一般 'DllImport'。 + + + + The specified value '{0}' for '{1}' is not supported by source-generated P/Invokes. If the specified configuration is required, use a regular `DllImport` instead. + 来源產生的 P/Invokes 不支援為'{0}'指定的值 '{1}'。如果需要指定的設定,請改用一般 'DllImport'。 + + + + Specified configuration is not supported by source-generated P/Invokes. + 来源產生的 P/Invokes 不支援指定的設定。 + + + + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' is contained in a type '{1}' that is not marked 'partial'. P/Invoke source generation will ignore method '{0}'. + + + + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic. + + + + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + Method '{0}' should be 'static', 'partial', and non-generic when marked with 'LibraryImportAttribute'. P/Invoke source generation will ignore method '{0}'. + + + + Invalid 'LibraryImportAttribute' usage + Invalid 'LibraryImportAttribute' usage + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' is invalid. + 'StringMarshalling' 和 'StringMarshallingCustomType' 的設定無效。 + + + + The configuration of 'StringMarshalling' and 'StringMarshallingCustomType' on method '{0}' is invalid. {1} + 方法 '{0}' 上的 'StringMarshalling' 和 'StringMarshallingCustomType' 設定無效。{1} + {1} is a message containing additional details about what is not valid + + + 'StringMarshallingCustomType' must be specified when 'StringMarshalling' is set to 'StringMarshalling.Custom'. + 當 'StringMarshalling' 設定為 'StringMarshalling.Custom' 時,必須指定 'StringMarshallingCustomType'。 + + + + 'StringMarshalling' should be set to 'StringMarshalling.Custom' when 'StringMarshallingCustomType' is specified. + 指定 'StringMarshallingCustomType' 時,'StringMarshalling' 應設定為 'StringMarshalling.Custom'。 + + + + For types that are not supported by source-generated P/Invokes, the resulting P/Invoke will rely on the underlying runtime to marshal the specified type. + 對於來源產生的 P/Invokes 不支援的類型,產生的 P/Invoke 將依賴基礎運行時間來封送指定的類型。 + + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of parameter '{1}'. + 来源產生的 P/Invokes 不支援類型 '{0}'。產生的来源將不會處理參數 '{1}' 的排列。 + + + + {0} The generated source will not handle marshalling of parameter '{1}'. + {0} 產生的来源将不會處理參數 '{1}' 的排列。 + {0} is a message containing additional details about what is not supported +{1} is the name of the parameter + + + The type '{0}' is not supported by source-generated P/Invokes. The generated source will not handle marshalling of the return value of method '{1}'. + 来源產生的 P/Invokes 不支援類型 '{0}'。產生的來源將不會處理方法 '{1}' 的傳回值排列。 + + + + {0} The generated source will not handle marshalling of the return value of method '{1}'. + {0} 產生的來源將不會處理方法 '{1}' 之傳回值的排列。 + {0} is a message containing additional details about what is not supported +{1} is the name of the method + + + Specified type is not supported by source-generated P/Invokes + 来源產生的 P/Invokes 不支援指定的類型。 + + + + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/UnreachableException.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/UnreachableException.cs new file mode 100644 index 0000000000000..203657801ccc8 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/UnreachableException.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.Interop +{ + /// + /// An exception that should be thrown on code-paths that are unreachable. + /// + internal sealed class UnreachableException : Exception + { + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VirtualMethodIndexData.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VirtualMethodIndexData.cs new file mode 100644 index 0000000000000..99f27201a9af3 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VirtualMethodIndexData.cs @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.Interop +{ + /// + /// VirtualMethodIndexAttribute data + /// + internal sealed record VirtualMethodIndexData(int Index) : InteropAttributeData + { + public bool ImplicitThisParameter { get; init; } + + public MarshalDirection Direction { get; init; } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs new file mode 100644 index 0000000000000..0805cef07c7eb --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs @@ -0,0 +1,425 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +[assembly: System.Resources.NeutralResourcesLanguage("en-US")] + +namespace Microsoft.Interop +{ + [Generator] + public sealed class VtableIndexStubGenerator : IIncrementalGenerator + { + internal sealed record IncrementalStubGenerationContext( + SignatureContext SignatureContext, + ContainingSyntaxContext ContainingSyntaxContext, + ContainingSyntax StubMethodSyntaxTemplate, + MethodSignatureDiagnosticLocations DiagnosticLocation, + SequenceEqualImmutableArray CallingConvention, + VirtualMethodIndexData VtableIndexData, + MarshallingGeneratorFactoryKey<(TargetFramework TargetFramework, Version TargetFrameworkVersion)> GeneratorFactory, + ManagedTypeInfo TypeKeyType, + ManagedTypeInfo TypeKeyOwner, + SequenceEqualImmutableArray Diagnostics); + + public static class StepNames + { + public const string CalculateStubInformation = nameof(CalculateStubInformation); + public const string GenerateManagedToNativeStub = nameof(GenerateManagedToNativeStub); + } + + public void Initialize(IncrementalGeneratorInitializationContext context) + { + var attributedMethods = context.SyntaxProvider + .ForAttributeWithMetadataName( + TypeNames.VirtualMethodIndexAttribute, + static (node, ct) => node is MethodDeclarationSyntax, + static (context, ct) => context.TargetSymbol is IMethodSymbol methodSymbol + ? new { Syntax = (MethodDeclarationSyntax)context.TargetNode, Symbol = methodSymbol } + : null) + .Where( + static modelData => modelData is not null); + + var methodsWithDiagnostics = attributedMethods.Select(static (data, ct) => + { + Diagnostic? diagnostic = GetDiagnosticIfInvalidMethodForGeneration(data.Syntax, data.Symbol); + return new { data.Syntax, data.Symbol, Diagnostic = diagnostic }; + }); + + var methodsToGenerate = methodsWithDiagnostics.Where(static data => data.Diagnostic is null); + var invalidMethodDiagnostics = methodsWithDiagnostics.Where(static data => data.Diagnostic is not null); + + context.RegisterSourceOutput(invalidMethodDiagnostics, static (context, invalidMethod) => + { + context.ReportDiagnostic(invalidMethod.Diagnostic); + }); + + IncrementalValuesProvider generateStubInformation = methodsToGenerate + .Combine(context.CreateStubEnvironmentProvider()) + .Select(static (data, ct) => new + { + data.Left.Syntax, + data.Left.Symbol, + Environment = data.Right + }) + .Select( + static (data, ct) => CalculateStubInformation(data.Syntax, data.Symbol, data.Environment, ct) + ) + .WithTrackingName(StepNames.CalculateStubInformation); + + IncrementalValuesProvider<(MemberDeclarationSyntax, ImmutableArray)> generateManagedToNativeStub = generateStubInformation + .Where(data => data.VtableIndexData.Direction is MarshalDirection.ManagedToUnmanaged or MarshalDirection.Bidirectional) + .Select( + static (data, ct) => GenerateManagedToNativeStub(data) + ) + .WithComparer(Comparers.GeneratedSyntax) + .WithTrackingName(StepNames.GenerateManagedToNativeStub); + + context.RegisterDiagnostics(generateManagedToNativeStub.SelectMany((stubInfo, ct) => stubInfo.Item2)); + + context.RegisterConcatenatedSyntaxOutputs(generateManagedToNativeStub.Select((data, ct) => data.Item1), "ManagedToNativeStubs.g.cs"); + + IncrementalValuesProvider generateNativeInterface = generateStubInformation + .Select(static (context, ct) => context.ContainingSyntaxContext) + .Collect() + .SelectMany(static (syntaxContexts, ct) => syntaxContexts.Distinct()) + .Select(static (context, ct) => GenerateNativeInterfaceMetadata(context)); + + context.RegisterConcatenatedSyntaxOutputs(generateNativeInterface, "NativeInterfaces.g.cs"); + } + + private static ImmutableArray GenerateCallConvSyntaxFromAttributes(AttributeData? suppressGCTransitionAttribute, AttributeData? unmanagedCallConvAttribute) + { + const string CallConvsField = "CallConvs"; + ImmutableArray.Builder callingConventions = ImmutableArray.CreateBuilder(); + + if (suppressGCTransitionAttribute is not null) + { + callingConventions.Add(FunctionPointerUnmanagedCallingConvention(Identifier("SuppressGCTransition"))); + } + if (unmanagedCallConvAttribute is not null) + { + foreach (KeyValuePair arg in unmanagedCallConvAttribute.NamedArguments) + { + if (arg.Key == CallConvsField) + { + foreach (TypedConstant callConv in arg.Value.Values) + { + ITypeSymbol callConvSymbol = (ITypeSymbol)callConv.Value!; + if (callConvSymbol.Name.StartsWith("CallConv", StringComparison.Ordinal)) + { + callingConventions.Add(FunctionPointerUnmanagedCallingConvention(Identifier(callConvSymbol.Name.Substring("CallConv".Length)))); + } + } + } + } + } + return callingConventions.ToImmutable(); + } + + private static SyntaxTokenList StripTriviaFromModifiers(SyntaxTokenList tokenList) + { + SyntaxToken[] strippedTokens = new SyntaxToken[tokenList.Count]; + for (int i = 0; i < tokenList.Count; i++) + { + strippedTokens[i] = tokenList[i].WithoutTrivia(); + } + return new SyntaxTokenList(strippedTokens); + } + + private static MemberDeclarationSyntax PrintGeneratedSource( + ContainingSyntax userDeclaredMethod, + ContainingSyntax originalInterfaceType, + SignatureContext stub, + BlockSyntax stubCode) + { + // Create stub function + return MethodDeclaration(stub.StubReturnType, userDeclaredMethod.Identifier) + .WithExplicitInterfaceSpecifier(ExplicitInterfaceSpecifier(IdentifierName(originalInterfaceType.Identifier))) + .AddAttributeLists(stub.AdditionalAttributes.ToArray()) + .WithModifiers(StripTriviaFromModifiers(userDeclaredMethod.Modifiers)) + .WithParameterList(ParameterList(SeparatedList(stub.StubParameters))) + .WithBody(stubCode); + } + + private static VirtualMethodIndexData? ProcessVirtualMethodIndexAttribute(AttributeData attrData) + { + // Found the attribute, but it has an error so report the error. + // This is most likely an issue with targeting an incorrect TFM. + if (attrData.AttributeClass?.TypeKind is null or TypeKind.Error) + { + return null; + } + + var namedArguments = ImmutableDictionary.CreateRange(attrData.NamedArguments); + + if (attrData.ConstructorArguments.Length == 0 || attrData.ConstructorArguments[0].Value is not int) + { + return null; + } + + MarshalDirection direction = MarshalDirection.Bidirectional; + bool implicitThis = true; + if (namedArguments.TryGetValue(nameof(VirtualMethodIndexData.Direction), out TypedConstant directionValue)) + { + // TypedConstant's Value property only contains primitive values. + if (directionValue.Value is not int) + { + return null; + } + // A boxed primitive can be unboxed to an enum with the same underlying type. + direction = (MarshalDirection)directionValue.Value!; + } + if (namedArguments.TryGetValue(nameof(VirtualMethodIndexData.ImplicitThisParameter), out TypedConstant implicitThisValue)) + { + if (implicitThisValue.Value is not bool) + { + return null; + } + implicitThis = (bool)implicitThisValue.Value!; + } + + return new VirtualMethodIndexData((int)attrData.ConstructorArguments[0].Value).WithValuesFromNamedArguments(namedArguments) with + { + Direction = direction, + ImplicitThisParameter = implicitThis + }; + } + + private static IncrementalStubGenerationContext CalculateStubInformation(MethodDeclarationSyntax syntax, IMethodSymbol symbol, StubEnvironment environment, CancellationToken ct) + { + ct.ThrowIfCancellationRequested(); + INamedTypeSymbol? lcidConversionAttrType = environment.Compilation.GetTypeByMetadataName(TypeNames.LCIDConversionAttribute); + INamedTypeSymbol? suppressGCTransitionAttrType = environment.Compilation.GetTypeByMetadataName(TypeNames.SuppressGCTransitionAttribute); + INamedTypeSymbol? unmanagedCallConvAttrType = environment.Compilation.GetTypeByMetadataName(TypeNames.UnmanagedCallConvAttribute); + INamedTypeSymbol iUnmanagedInterfaceTypeType = environment.Compilation.GetTypeByMetadataName(TypeNames.IUnmanagedInterfaceType_Metadata)!; + // Get any attributes of interest on the method + AttributeData? virtualMethodIndexAttr = null; + AttributeData? lcidConversionAttr = null; + AttributeData? suppressGCTransitionAttribute = null; + AttributeData? unmanagedCallConvAttribute = null; + foreach (AttributeData attr in symbol.GetAttributes()) + { + if (attr.AttributeClass is not null + && attr.AttributeClass.ToDisplayString() == TypeNames.VirtualMethodIndexAttribute) + { + virtualMethodIndexAttr = attr; + } + else if (lcidConversionAttrType is not null && SymbolEqualityComparer.Default.Equals(attr.AttributeClass, lcidConversionAttrType)) + { + lcidConversionAttr = attr; + } + else if (suppressGCTransitionAttrType is not null && SymbolEqualityComparer.Default.Equals(attr.AttributeClass, suppressGCTransitionAttrType)) + { + suppressGCTransitionAttribute = attr; + } + else if (unmanagedCallConvAttrType is not null && SymbolEqualityComparer.Default.Equals(attr.AttributeClass, unmanagedCallConvAttrType)) + { + unmanagedCallConvAttribute = attr; + } + } + + Debug.Assert(virtualMethodIndexAttr is not null); + + var generatorDiagnostics = new GeneratorDiagnostics(); + + // Process the LibraryImport attribute + VirtualMethodIndexData? virtualMethodIndexData = ProcessVirtualMethodIndexAttribute(virtualMethodIndexAttr!); + + if (virtualMethodIndexData is null) + { + virtualMethodIndexData = new VirtualMethodIndexData(-1); + } + else if (virtualMethodIndexData.Index < 0) + { + // Report missing or invalid index + } + + if (virtualMethodIndexData.IsUserDefined.HasFlag(InteropAttributeMember.StringMarshalling)) + { + // User specified StringMarshalling.Custom without specifying StringMarshallingCustomType + if (virtualMethodIndexData.StringMarshalling == StringMarshalling.Custom && virtualMethodIndexData.StringMarshallingCustomType is null) + { + generatorDiagnostics.ReportInvalidStringMarshallingConfiguration( + virtualMethodIndexAttr, symbol.Name, SR.InvalidStringMarshallingConfigurationMissingCustomType); + } + + // User specified something other than StringMarshalling.Custom while specifying StringMarshallingCustomType + if (virtualMethodIndexData.StringMarshalling != StringMarshalling.Custom && virtualMethodIndexData.StringMarshallingCustomType is not null) + { + generatorDiagnostics.ReportInvalidStringMarshallingConfiguration( + virtualMethodIndexAttr, symbol.Name, SR.InvalidStringMarshallingConfigurationNotCustom); + } + } + + if (!virtualMethodIndexData.ImplicitThisParameter && virtualMethodIndexData.Direction is MarshalDirection.UnmanagedToManaged or MarshalDirection.Bidirectional) + { + // Report invalid configuration + } + + if (lcidConversionAttr is not null) + { + // Using LCIDConversion with source-generated interop is not supported + generatorDiagnostics.ReportConfigurationNotSupported(lcidConversionAttr, nameof(TypeNames.LCIDConversionAttribute)); + } + + // Create the stub. + var signatureContext = SignatureContext.Create(symbol, DefaultMarshallingInfoParser.Create(environment, generatorDiagnostics, symbol, virtualMethodIndexData, virtualMethodIndexAttr), environment, typeof(VtableIndexStubGenerator).Assembly); + + var containingSyntaxContext = new ContainingSyntaxContext(syntax); + + var methodSyntaxTemplate = new ContainingSyntax(syntax.Modifiers.StripTriviaFromTokens(), SyntaxKind.MethodDeclaration, syntax.Identifier, syntax.TypeParameterList); + + ImmutableArray callConv = GenerateCallConvSyntaxFromAttributes(suppressGCTransitionAttribute, unmanagedCallConvAttribute); + + var typeKeyOwner = ManagedTypeInfo.CreateTypeInfoForTypeSymbol(symbol.ContainingType); + ManagedTypeInfo typeKeyType = SpecialTypeInfo.Byte; + + INamedTypeSymbol? iUnmanagedInterfaceTypeInstantiation = symbol.ContainingType.AllInterfaces.FirstOrDefault(iface => SymbolEqualityComparer.Default.Equals(iface.OriginalDefinition, iUnmanagedInterfaceTypeType)); + if (iUnmanagedInterfaceTypeInstantiation is null) + { + // Report invalid configuration + } + else + { + typeKeyType = ManagedTypeInfo.CreateTypeInfoForTypeSymbol(iUnmanagedInterfaceTypeInstantiation.TypeArguments[0]); + } + + return new IncrementalStubGenerationContext( + signatureContext, + containingSyntaxContext, + methodSyntaxTemplate, + new MethodSignatureDiagnosticLocations(syntax), + new SequenceEqualImmutableArray(callConv, SyntaxEquivalentComparer.Instance), + virtualMethodIndexData, + ComInterfaceGeneratorHelpers.CreateGeneratorFactory(environment), + typeKeyType, + typeKeyOwner, + new SequenceEqualImmutableArray(generatorDiagnostics.Diagnostics.ToImmutableArray())); + } + + private static IMarshallingGeneratorFactory GetMarshallingGeneratorFactory(StubEnvironment env) + { + IAssemblySymbol coreLibraryAssembly = env.Compilation.GetSpecialType(SpecialType.System_Object).ContainingAssembly; + ITypeSymbol? disabledRuntimeMarshallingAttributeType = coreLibraryAssembly.GetTypeByMetadataName(TypeNames.System_Runtime_CompilerServices_DisableRuntimeMarshallingAttribute); + bool runtimeMarshallingDisabled = disabledRuntimeMarshallingAttributeType is not null + && env.Compilation.Assembly.GetAttributes().Any(attr => SymbolEqualityComparer.Default.Equals(attr.AttributeClass, disabledRuntimeMarshallingAttributeType)); + InteropGenerationOptions options = new(UseMarshalType: true); + IMarshallingGeneratorFactory generatorFactory; + + generatorFactory = new UnsupportedMarshallingFactory(); + generatorFactory = new NoMarshallingInfoErrorMarshallingFactory(generatorFactory); + generatorFactory = new MarshalAsMarshallingGeneratorFactory(options, generatorFactory); + + IMarshallingGeneratorFactory elementFactory = new AttributedMarshallingModelGeneratorFactory( + new CharMarshallingGeneratorFactory(generatorFactory, useBlittableMarshallerForUtf16: true), new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, MarshalMode.ElementIn, MarshalMode.ElementRef, MarshalMode.ElementOut)); + // We don't need to include the later generator factories for collection elements + // as the later generator factories only apply to parameters. + generatorFactory = new AttributedMarshallingModelGeneratorFactory(generatorFactory, elementFactory, new AttributedMarshallingModelOptions(runtimeMarshallingDisabled, MarshalMode.ManagedToUnmanagedIn, MarshalMode.ManagedToUnmanagedRef, MarshalMode.ManagedToUnmanagedOut)); + + generatorFactory = new ByValueContentsMarshalKindValidator(generatorFactory); + return generatorFactory; + } + + private static (MemberDeclarationSyntax, ImmutableArray) GenerateManagedToNativeStub( + IncrementalStubGenerationContext methodStub) + { + var diagnostics = new GeneratorDiagnostics(); + + // Generate stub code + var stubGenerator = new ManagedToNativeVTableMethodGenerator( + methodStub.GeneratorFactory.Key.TargetFramework, + methodStub.GeneratorFactory.Key.TargetFrameworkVersion, + methodStub.SignatureContext.ElementTypeInformation, + methodStub.VtableIndexData.SetLastError, + methodStub.VtableIndexData.ImplicitThisParameter, + (elementInfo, ex) => + { + diagnostics.ReportMarshallingNotSupported(methodStub.DiagnosticLocation, elementInfo, ex.NotSupportedDetails); + }, + methodStub.GeneratorFactory.GeneratorFactory); + + BlockSyntax code = stubGenerator.GenerateStubBody( + methodStub.VtableIndexData.Index, + methodStub.CallingConvention.Array, + methodStub.TypeKeyOwner.Syntax, + methodStub.TypeKeyType); + + return ( + methodStub.ContainingSyntaxContext.AddContainingSyntax( + new ContainingSyntax( + TokenList(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.PartialKeyword)), + SyntaxKind.InterfaceDeclaration, + Identifier("Native"), + null)) + .WrapMemberInContainingSyntaxWithUnsafeModifier( + PrintGeneratedSource( + methodStub.StubMethodSyntaxTemplate, + methodStub.ContainingSyntaxContext.ContainingSyntax[0], + methodStub.SignatureContext, + code)), + methodStub.Diagnostics.Array.AddRange(diagnostics.Diagnostics)); + } + + private static bool ShouldVisitNode(SyntaxNode syntaxNode) + { + // We only support C# method declarations. + if (syntaxNode.Language != LanguageNames.CSharp + || !syntaxNode.IsKind(SyntaxKind.MethodDeclaration)) + { + return false; + } + + // Filter out methods with no attributes early. + return ((MethodDeclarationSyntax)syntaxNode).AttributeLists.Count > 0; + } + + private static Diagnostic? GetDiagnosticIfInvalidMethodForGeneration(MethodDeclarationSyntax methodSyntax, IMethodSymbol method) + { + // Verify the method has no generic types or defined implementation + // and is not marked static or sealed + if (methodSyntax.TypeParameterList is not null + || methodSyntax.Body is not null + || methodSyntax.Modifiers.Any(SyntaxKind.StaticKeyword) + || methodSyntax.Modifiers.Any(SyntaxKind.SealedKeyword)) + { + return Diagnostic.Create(GeneratorDiagnostics.InvalidAttributedMethodSignature, methodSyntax.Identifier.GetLocation(), method.Name); + } + + // Verify that the types the method is declared in are marked partial. + for (SyntaxNode? parentNode = methodSyntax.Parent; parentNode is TypeDeclarationSyntax typeDecl; parentNode = parentNode.Parent) + { + if (!typeDecl.Modifiers.Any(SyntaxKind.PartialKeyword)) + { + return Diagnostic.Create(GeneratorDiagnostics.InvalidAttributedMethodContainingTypeMissingModifiers, methodSyntax.Identifier.GetLocation(), method.Name, typeDecl.Identifier); + } + } + + // Verify the method does not have a ref return + if (method.ReturnsByRef || method.ReturnsByRefReadonly) + { + return Diagnostic.Create(GeneratorDiagnostics.ReturnConfigurationNotSupported, methodSyntax.Identifier.GetLocation(), "ref return", method.ToDisplayString()); + } + + return null; + } + + private static MemberDeclarationSyntax GenerateNativeInterfaceMetadata(ContainingSyntaxContext context) + { + return context.WrapMemberInContainingSyntaxWithUnsafeModifier( + InterfaceDeclaration("Native") + .WithModifiers(TokenList(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.PartialKeyword))) + .WithBaseList(BaseList(SingletonSeparatedList((BaseTypeSyntax)SimpleBaseType(IdentifierName(context.ContainingSyntax[0].Identifier))))) + .AddAttributeLists(AttributeList(SingletonSeparatedList(Attribute(ParseName(TypeNames.System_Runtime_InteropServices_DynamicInterfaceCastableImplementationAttribute)))))); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/DefaultMarshallingInfoParser.cs b/src/libraries/System.Runtime.InteropServices/gen/Common/DefaultMarshallingInfoParser.cs similarity index 100% rename from src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/DefaultMarshallingInfoParser.cs rename to src/libraries/System.Runtime.InteropServices/gen/Common/DefaultMarshallingInfoParser.cs diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.csproj b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.csproj index 0a331d098e377..7fff2e5413271 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.csproj +++ b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/LibraryImportGenerator.csproj @@ -26,6 +26,7 @@ + diff --git a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/MethodSignatureDiagnosticLocations.cs b/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/MethodSignatureDiagnosticLocations.cs deleted file mode 100644 index 80607c5668722..0000000000000 --- a/src/libraries/System.Runtime.InteropServices/gen/LibraryImportGenerator/MethodSignatureDiagnosticLocations.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Immutable; -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Syntax; - -namespace Microsoft.Interop -{ - public sealed record MethodSignatureDiagnosticLocations(string MethodIdentifier, ImmutableArray ManagedParameterLocations, Location FallbackLocation) - { - public MethodSignatureDiagnosticLocations(MethodDeclarationSyntax syntax) - : this(syntax.Identifier.Text, syntax.ParameterList.Parameters.Select(p => p.Identifier.GetLocation()).ToImmutableArray(), syntax.Identifier.GetLocation()) - { - } - - public bool Equals(MethodSignatureDiagnosticLocations other) - { - return MethodIdentifier == other.MethodIdentifier - && ManagedParameterLocations.SequenceEqual(other.ManagedParameterLocations) - && FallbackLocation.Equals(other.FallbackLocation); - } - - public override int GetHashCode() => throw new UnreachableException(); - } -} diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/BoundGenerators.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/BoundGenerators.cs index 90ca43a64abbd..b1f95c1903a1c 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/BoundGenerators.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/BoundGenerators.cs @@ -101,10 +101,16 @@ static IEnumerable GetInfoDependencies(TypePositionInfo info) static int GetInfoIndex(TypePositionInfo info) { + // A TypePositionInfo needs to have either a managed or native index. + // We use negative values of the native index to distinguish them from the managed index. if (info.ManagedIndex == TypePositionInfo.UnsetIndex) { - // A TypePositionInfo needs to have either a managed or native index. - // We use negative values of the native index to distinguish them from the managed index. + if (info.NativeIndex == 0) + { + // If we don't have a managed index and the native index is zero, use ReturnIndex + 1 as our + // index to avoid conflict with managed parameter 0. + return TypePositionInfo.ReturnIndex + 1; + } return -info.NativeIndex; } return info.ManagedIndex; diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ContainingSyntaxContext.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ContainingSyntaxContext.cs index 567d5c2f024b9..69b2e1c02b58c 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ContainingSyntaxContext.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ContainingSyntaxContext.cs @@ -34,7 +34,7 @@ public ContainingSyntaxContext(MemberDeclarationSyntax memberDeclaration) public ContainingSyntaxContext AddContainingSyntax(ContainingSyntax nestedType) { - return this with { ContainingSyntax = ContainingSyntax.Add(nestedType) }; + return this with { ContainingSyntax = ContainingSyntax.Insert(0, nestedType) }; } private static ImmutableArray GetContainingTypes(MemberDeclarationSyntax memberDeclaration) @@ -42,7 +42,6 @@ private static ImmutableArray GetContainingTypes(MemberDeclara ImmutableArray.Builder containingTypeInfoBuilder = ImmutableArray.CreateBuilder(); for (SyntaxNode? parent = memberDeclaration.Parent; parent is TypeDeclarationSyntax typeDeclaration; parent = parent.Parent) { - containingTypeInfoBuilder.Add(new ContainingSyntax(typeDeclaration.Modifiers.StripTriviaFromTokens(), typeDeclaration.Kind(), typeDeclaration.Identifier.WithoutTrivia(), typeDeclaration.TypeParameterList)); } @@ -75,7 +74,15 @@ public bool Equals(ContainingSyntaxContext other) && ContainingNamespace == other.ContainingNamespace; } - public override int GetHashCode() => throw new UnreachableException(); + public override int GetHashCode() + { + int code = ContainingNamespace?.GetHashCode() ?? 0; + foreach (ContainingSyntax containingSyntax in ContainingSyntax) + { + code ^= containingSyntax.Identifier.Value.GetHashCode(); + } + return code; + } public MemberDeclarationSyntax WrapMemberInContainingSyntaxWithUnsafeModifier(MemberDeclarationSyntax member) { diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/CustomTypeMarshallingDirection.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/CustomTypeMarshallingDirection.cs deleted file mode 100644 index 25dd1dd095402..0000000000000 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/CustomTypeMarshallingDirection.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.ComponentModel; - - -namespace Microsoft.Interop -{ - /// - /// A direction of marshalling data into or out of the managed environment - /// - [Flags] - public enum CustomTypeMarshallingDirection - { - /// - /// No marshalling direction - /// - [EditorBrowsable(EditorBrowsableState.Never)] - None = 0, - /// - /// Marshalling from a managed environment to an unmanaged environment - /// - In = 0x1, - /// - /// Marshalling from an unmanaged environment to a managed environment - /// - Out = 0x2, - /// - /// Marshalling to and from managed and unmanaged environments - /// - Ref = In | Out, - } -} diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManagedTypeInfo.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManagedTypeInfo.cs index c85f6bdec05e0..647fc427baf48 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManagedTypeInfo.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/ManagedTypeInfo.cs @@ -74,6 +74,7 @@ public sealed record SpecialTypeInfo(string FullTypeName, string DiagnosticForma public static readonly SpecialTypeInfo Void = new("void", "void", SpecialType.System_Void); public static readonly SpecialTypeInfo String = new("string", "string", SpecialType.System_String); public static readonly SpecialTypeInfo Boolean = new("bool", "bool", SpecialType.System_Boolean); + public static readonly SpecialTypeInfo IntPtr = new("System.IntPtr", "System.IntPtr", SpecialType.System_IntPtr); public bool Equals(SpecialTypeInfo? other) { diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/MethodSignatureDiagnosticLocations.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MethodSignatureDiagnosticLocations.cs similarity index 100% rename from src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/MethodSignatureDiagnosticLocations.cs rename to src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/MethodSignatureDiagnosticLocations.cs diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj index e6e1b9f9e41a9..a0b93d14687e1 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/Microsoft.Interop.SourceGeneration.csproj @@ -14,6 +14,10 @@ + + + + diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/StubCodeContext.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/StubCodeContext.cs index abf39fe458379..fe10c970d2eb3 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/StubCodeContext.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/StubCodeContext.cs @@ -80,11 +80,7 @@ public enum Stage /// public Stage CurrentStage { get; init; } = Stage.Invalid; - /// - /// CustomTypeMarshallingDirection.In means method import like [LibraryImport]. - /// CustomTypeMarshallingDirection.Out means method export like in [UnmanagedCallersOnly] or in [JSExport] - /// - public CustomTypeMarshallingDirection Direction { get; init; } = CustomTypeMarshallingDirection.In; + public MarshalDirection Direction { get; init; } = MarshalDirection.ManagedToUnmanaged; /// /// Gets the currently targeted framework and version for stub code generation. diff --git a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs index 7059257114698..e999aed83cdbb 100644 --- a/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs +++ b/src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs @@ -27,6 +27,13 @@ public static class TypeNames public const string SuppressGCTransitionAttribute = "System.Runtime.InteropServices.SuppressGCTransitionAttribute"; public const string UnmanagedCallConvAttribute = "System.Runtime.InteropServices.UnmanagedCallConvAttribute"; + + public const string VirtualMethodIndexAttribute = "System.Runtime.InteropServices.Marshalling.VirtualMethodIndexAttribute"; + + public const string IUnmanagedVirtualMethodTableProvider = "System.Runtime.InteropServices.IUnmanagedVirtualMethodTableProvider"; + + public const string IUnmanagedInterfaceType_Metadata = "System.Runtime.InteropServices.IUnmanagedInterfaceType`1"; + public const string System_Span_Metadata = "System.Span`1"; public const string System_Span = "System.Span"; public const string System_ReadOnlySpan_Metadata = "System.ReadOnlySpan`1"; @@ -80,5 +87,7 @@ public static string MarshalEx(InteropGenerationOptions options) public const string DllImportSearchPath = "System.Runtime.InteropServices.DllImportSearchPath"; public const string System_CodeDom_Compiler_GeneratedCodeAttribute = "System.CodeDom.Compiler.GeneratedCodeAttribute"; + + public const string System_Runtime_InteropServices_DynamicInterfaceCastableImplementationAttribute = "System.Runtime.InteropServices.DynamicInterfaceCastableImplementationAttribute"; } } diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/Ancillary.Interop.csproj b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/Ancillary.Interop.csproj index 629c77c4b3493..e3404e9871a84 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/Ancillary.Interop.csproj +++ b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/Ancillary.Interop.csproj @@ -3,11 +3,14 @@ Microsoft.Interop.Ancillary $(NetCoreAppCurrent) - System.Runtime.InteropServices + System.Runtime.InteropServices.Marshalling enable true APIs required for usage of the LibraryImportGenerator and related tools. - $(DefineConstants);LIBRARYIMPORT_GENERATOR_TEST + $(DefineConstants);ANCILLARY_INTEROP + + + diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IUnmanagedVirtualMethodTableProvider.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IUnmanagedVirtualMethodTableProvider.cs new file mode 100644 index 0000000000000..9b77ec6493b8a --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IUnmanagedVirtualMethodTableProvider.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace System.Runtime.InteropServices +{ + public readonly ref struct VirtualMethodTableInfo + { + public VirtualMethodTableInfo(IntPtr thisPointer, ReadOnlySpan virtualMethodTable) + { + ThisPointer = thisPointer; + VirtualMethodTable = virtualMethodTable; + } + + public IntPtr ThisPointer { get; } + public ReadOnlySpan VirtualMethodTable { get; } + + public void Deconstruct(out IntPtr thisPointer, out ReadOnlySpan virtualMethodTable) + { + thisPointer = ThisPointer; + virtualMethodTable = VirtualMethodTable; + } + } + + public interface IUnmanagedVirtualMethodTableProvider where T : IEquatable + { + protected VirtualMethodTableInfo GetVirtualMethodTableInfoForKey(T typeKey); + + public sealed VirtualMethodTableInfo GetVirtualMethodTableInfoForKey() + where TUnmanagedInterfaceType : IUnmanagedInterfaceType + { + return GetVirtualMethodTableInfoForKey(TUnmanagedInterfaceType.TypeKey); + } + } + + + public interface IUnmanagedInterfaceType where T : IEquatable + { + public abstract static T TypeKey { get; } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/VirtualMethodIndexAttribute.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/VirtualMethodIndexAttribute.cs new file mode 100644 index 0000000000000..52f1341427211 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/VirtualMethodIndexAttribute.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices.Marshalling; +using System.Text; +using System.Threading.Tasks; + +namespace System.Runtime.InteropServices.Marshalling +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class VirtualMethodIndexAttribute : Attribute + { + public VirtualMethodIndexAttribute(int index) + { + Index = index; + } + + public int Index { get; } + + public bool ImplicitThisParameter { get; set; } = true; + + public MarshalDirection Direction { get; set; } = MarshalDirection.Bidirectional; + + /// + /// Gets or sets how to marshal string arguments to the method. + /// + /// + /// If this field is set to a value other than , + /// must not be specified. + /// + public StringMarshalling StringMarshalling { get; set; } + + /// + /// Gets or sets the used to control how string arguments to the method are marshalled. + /// + /// + /// If this field is specified, must not be specified + /// or must be set to . + /// + public Type? StringMarshallingCustomType { get; set; } + + /// + /// Gets or sets whether the callee sets an error (SetLastError on Windows or errno + /// on other platforms) before returning from the attributed method. + /// + public bool SetLastError { get; set; } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/AssemblyInfo.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/AssemblyInfo.cs new file mode 100644 index 0000000000000..6f8836d701825 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/AssemblyInfo.cs @@ -0,0 +1,7 @@ +using Xunit; + +// Disable all tests in the assembly here. We'd prefer to disable them in src/libraries/tests.proj +// but we can't disable tests just based on RuntimeFlavor there as we build our tests once per target, not per target and runtime flavor +// in our split jobs (where we build libraries in one job and the runtime in another). +// As a result, we'll disable these tests here for now. +[assembly:SkipOnMono("All tests here use RuntimeHelpers.AllocateTypeAssociatedMemory, which is not implemented on Mono")] \ No newline at end of file diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/ComInterfaceGenerator.Tests.csproj b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/ComInterfaceGenerator.Tests.csproj new file mode 100644 index 0000000000000..56e29a19f19e1 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/ComInterfaceGenerator.Tests.csproj @@ -0,0 +1,23 @@ + + + $(NetCoreAppCurrent) + false + Preview + true + true + + false + + + + + + + + + + + + + + diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/Constants.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/Constants.cs new file mode 100644 index 0000000000000..0ac4254a02287 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/Constants.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace ComInterfaceGenerator.Tests +{ + partial class NativeExportsNE + { + public const string NativeExportsNE_Binary = "Microsoft.Interop.Tests." + nameof(NativeExportsNE); + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/Directory.Build.props b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/Directory.Build.props new file mode 100644 index 0000000000000..fa9c3a4001db5 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/Directory.Build.props @@ -0,0 +1,7 @@ + + + + + true + + diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/ImplicitThisTests.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/ImplicitThisTests.cs new file mode 100644 index 0000000000000..fa2e70015200d --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/ImplicitThisTests.cs @@ -0,0 +1,79 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace ComInterfaceGenerator.Tests +{ + internal unsafe partial class NativeExportsNE + { + internal partial class ImplicitThis + { + public readonly record struct NoCasting; + + internal partial interface INativeObject : IUnmanagedInterfaceType + { + static NoCasting IUnmanagedInterfaceType.TypeKey => default; + + [VirtualMethodIndex(0, ImplicitThisParameter = true)] + int GetData(); + [VirtualMethodIndex(1, ImplicitThisParameter = true)] + void SetData(int x); + } + + [NativeMarshalling(typeof(NativeObjectMarshaller))] + public class NativeObject : INativeObject.Native, IUnmanagedVirtualMethodTableProvider, IDisposable + { + private readonly void* _pointer; + + public NativeObject(void* pointer) + { + _pointer = pointer; + } + + public VirtualMethodTableInfo GetVirtualMethodTableInfoForKey(NoCasting typeKey) => new VirtualMethodTableInfo((IntPtr)_pointer, new ReadOnlySpan(*(void**)_pointer, 2)); + + public void Dispose() + { + DeleteNativeObject(_pointer); + } + } + + [CustomMarshaller(typeof(NativeObject), MarshalMode.ManagedToUnmanagedOut, typeof(NativeObjectMarshaller))] + static class NativeObjectMarshaller + { + public static NativeObject ConvertToManaged(void* value) => new NativeObject(value); + } + + [LibraryImport(NativeExportsNE_Binary, EntryPoint = "new_native_object")] + public static partial NativeObject NewNativeObject(); + + [LibraryImport(NativeExportsNE_Binary, EntryPoint = "delete_native_object")] + public static partial void DeleteNativeObject(void* obj); + } + } + + public class ImplicitThisTests + { + [Fact] + public void ValidateImplicitThisFunctionCallsSucceed() + { + const int value = 42; + + using NativeExportsNE.ImplicitThis.NativeObject obj = NativeExportsNE.ImplicitThis.NewNativeObject(); + + NativeExportsNE.ImplicitThis.INativeObject nativeObjInterface = obj; + + nativeObjInterface.SetData(value); + + Assert.Equal(value, nativeObjInterface.GetData()); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/NoImplicitThisTests.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/NoImplicitThisTests.cs new file mode 100644 index 0000000000000..4219427a4a31f --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/NoImplicitThisTests.cs @@ -0,0 +1,69 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace ComInterfaceGenerator.Tests +{ + internal unsafe partial class NativeExportsNE + { + internal partial class NoImplicitThis + { + public readonly record struct NoCasting; + + internal partial interface IStaticMethodTable : IUnmanagedInterfaceType + { + static NoCasting IUnmanagedInterfaceType.TypeKey => default; + + [VirtualMethodIndex(0, ImplicitThisParameter = false)] + int Add(int x, int y); + [VirtualMethodIndex(1, ImplicitThisParameter = false)] + int Multiply(int x, int y); + } + + [NativeMarshalling(typeof(StaticMethodTableMarshaller))] + public class StaticMethodTable : IStaticMethodTable.Native, IUnmanagedVirtualMethodTableProvider + { + private readonly void* _vtableStart; + + public StaticMethodTable(void* vtableStart) + { + _vtableStart = vtableStart; + } + + public VirtualMethodTableInfo GetVirtualMethodTableInfoForKey(NoCasting typeKey) => new VirtualMethodTableInfo(IntPtr.Zero, new ReadOnlySpan(_vtableStart, 2)); + } + + [CustomMarshaller(typeof(StaticMethodTable), MarshalMode.ManagedToUnmanagedOut, typeof(StaticMethodTableMarshaller))] + static class StaticMethodTableMarshaller + { + public static StaticMethodTable ConvertToManaged(void* value) => new StaticMethodTable(value); + } + + [LibraryImport(NativeExportsNE_Binary, EntryPoint = "get_static_function_table")] + public static partial StaticMethodTable GetStaticFunctionTable(); + } + } + + public class NoImplicitThisTests + { + [Fact] + public void ValidateNoImplicitThisFunctionCallsSucceed() + { + int x = 7; + int y = 56; + + NativeExportsNE.NoImplicitThis.IStaticMethodTable staticMethodTable = NativeExportsNE.NoImplicitThis.GetStaticFunctionTable(); + + Assert.Equal(x + y, staticMethodTable.Add(x, y)); + Assert.Equal(x * y, staticMethodTable.Multiply(x, y)); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CallingConventionForwarding.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CallingConventionForwarding.cs new file mode 100644 index 0000000000000..606f432617fea --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CallingConventionForwarding.cs @@ -0,0 +1,218 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Metadata; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Operations; +using Microsoft.Interop.UnitTests; +using Xunit; + +namespace ComInterfaceGenerator.Unit.Tests +{ + public class CallingConventionForwarding + { + [Fact] + public async Task NoSpecifiedCallConvForwardsDefault() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + readonly record struct NoCasting {} + partial interface INativeAPI + { + public static readonly NoCasting TypeKey = default; + [VirtualMethodIndex(0)] + void Method(); + } + """; + Compilation comp = await TestUtils.CreateCompilation(source); + // Allow the Native nested type name to be missing in the pre-source-generator compilation + TestUtils.AssertPreSourceGeneratorCompilation(comp); + + var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator()); + + var signature = await FindFunctionPointerInvocationSignature(newComp, "INativeAPI", "Method"); + + Assert.Equal(SignatureCallingConvention.Unmanaged, signature.CallingConvention); + Assert.Empty(signature.UnmanagedCallingConventionTypes); + } + + [Fact] + public async Task SuppressGCTransitionAttributeForwarded() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + readonly record struct NoCasting {} + partial interface INativeAPI + { + public static readonly NoCasting TypeKey = default; + [SuppressGCTransitionAttribute] + [VirtualMethodIndex(0)] + void Method(); + } + """; + Compilation comp = await TestUtils.CreateCompilation(source); + // Allow the Native nested type name to be missing in the pre-source-generator compilation + TestUtils.AssertPreSourceGeneratorCompilation(comp); + + var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator()); + + var signature = await FindFunctionPointerInvocationSignature(newComp, "INativeAPI", "Method"); + + Assert.Equal(SignatureCallingConvention.Unmanaged, signature.CallingConvention); + Assert.Equal(newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvSuppressGCTransition"), Assert.Single(signature.UnmanagedCallingConventionTypes), SymbolEqualityComparer.Default); + } + + [Fact] + public async Task EmptyUnmanagedCallConvAttributeForwarded() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + readonly record struct NoCasting {} + partial interface INativeAPI + { + public static readonly NoCasting TypeKey = default; + [UnmanagedCallConv] + [VirtualMethodIndex(0)] + void Method(); + } + """; + Compilation comp = await TestUtils.CreateCompilation(source); + // Allow the Native nested type name to be missing in the pre-source-generator compilation + TestUtils.AssertPreSourceGeneratorCompilation(comp); + + var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator()); + + var signature = await FindFunctionPointerInvocationSignature(newComp, "INativeAPI", "Method"); + + Assert.Equal(SignatureCallingConvention.Unmanaged, signature.CallingConvention); + Assert.Empty(signature.UnmanagedCallingConventionTypes); + } + + [Fact] + public async Task SimpleUnmanagedCallConvAttributeForwarded() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + readonly record struct NoCasting {} + partial interface INativeAPI + { + public static readonly NoCasting TypeKey = default; + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] + [VirtualMethodIndex(0)] + void Method(); + } + """; + Compilation comp = await TestUtils.CreateCompilation(source); + // Allow the Native nested type name to be missing in the pre-source-generator compilation + TestUtils.AssertPreSourceGeneratorCompilation(comp); + + var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator()); + + var signature = await FindFunctionPointerInvocationSignature(newComp, "INativeAPI", "Method"); + + Assert.Equal(SignatureCallingConvention.CDecl, signature.CallingConvention); + Assert.Empty(signature.UnmanagedCallingConventionTypes); + } + + [Fact] + public async Task ComplexUnmanagedCallConvAttributeForwarded() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + readonly record struct NoCasting {} + partial interface INativeAPI + { + public static readonly NoCasting TypeKey = default; + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl), typeof(CallConvMemberFunction) })] + [VirtualMethodIndex(0)] + void Method(); + } + """; + Compilation comp = await TestUtils.CreateCompilation(source); + // Allow the Native nested type name to be missing in the pre-source-generator compilation + TestUtils.AssertPreSourceGeneratorCompilation(comp); + + var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator()); + + var signature = await FindFunctionPointerInvocationSignature(newComp, "INativeAPI", "Method"); + + Assert.Equal(SignatureCallingConvention.Unmanaged, signature.CallingConvention); + Assert.Equal(new[] + { + newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvCdecl"), + newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvMemberFunction"), + }, + signature.UnmanagedCallingConventionTypes, + SymbolEqualityComparer.Default); + } + + [Fact] + public async Task ComplexUnmanagedCallConvAttributeWithSuppressGCTransitionForwarded() + { + string source = """ + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.Marshalling; + + readonly record struct NoCasting {} + partial interface INativeAPI + { + public static readonly NoCasting TypeKey = default; + [SuppressGCTransition] + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl), typeof(CallConvMemberFunction) })] + [VirtualMethodIndex(0)] + void Method(); + } + """; + Compilation comp = await TestUtils.CreateCompilation(source); + // Allow the Native nested type name to be missing in the pre-source-generator compilation + TestUtils.AssertPreSourceGeneratorCompilation(comp); + + var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator()); + + var signature = await FindFunctionPointerInvocationSignature(newComp, "INativeAPI", "Method"); + + Assert.Equal(SignatureCallingConvention.Unmanaged, signature.CallingConvention); + Assert.Equal(new[] + { + newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvSuppressGCTransition"), + newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvCdecl"), + newComp.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConvMemberFunction"), + }, + signature.UnmanagedCallingConventionTypes, + SymbolEqualityComparer.Default); + } + + private static async Task FindFunctionPointerInvocationSignature(Compilation compilation, string userDefinedInterfaceName, string methodName) + { + INamedTypeSymbol? userDefinedInterface = compilation.Assembly.GetTypeByMetadataName(userDefinedInterfaceName); + Assert.NotNull(userDefinedInterface); + + INamedTypeSymbol generatedInterfaceImplementation = Assert.Single(userDefinedInterface.GetTypeMembers("Native")); + + IMethodSymbol methodImplementation = Assert.Single(generatedInterfaceImplementation.GetMembers($"{userDefinedInterfaceName}.{methodName}").OfType()); + + SyntaxNode emittedImplementationSyntax = await methodImplementation.DeclaringSyntaxReferences[0].GetSyntaxAsync(); + + SemanticModel model = compilation.GetSemanticModel(emittedImplementationSyntax.SyntaxTree); + + IOperation body = model.GetOperation(emittedImplementationSyntax)!; + + return Assert.Single(body.Descendants().OfType()).GetFunctionPointerSignature(); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs new file mode 100644 index 0000000000000..383e179504f0a --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs @@ -0,0 +1,302 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.Interop.UnitTests; + +namespace ComInterfaceGenerator.Unit.Tests +{ + internal partial class CodeSnippets : ICustomMarshallingSignatureTestProvider + { + public static readonly string DisableRuntimeMarshalling = "[assembly:System.Runtime.CompilerServices.DisableRuntimeMarshalling]"; + public static readonly string UsingSystemRuntimeInteropServicesMarshalling = "using System.Runtime.InteropServices.Marshalling;"; + + public static string NativeInterfaceUsage() => @" +// Try using the generated native interface +sealed class NativeAPI : IUnmanagedVirtualMethodTableProvider, INativeAPI.Native +{ + public VirtualMethodTableInfo GetVirtualMethodTableInfoForKey(NoCasting typeKey) => throw null; +} +"; + + public static readonly string SpecifiedMethodIndexNoExplicitParameters = @" +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +readonly record struct NoCasting {} +partial interface INativeAPI : IUnmanagedInterfaceType +{ + static NoCasting IUnmanagedInterfaceType.TypeKey => default; + [VirtualMethodIndex(0)] + void Method(); +}" + NativeInterfaceUsage(); + + public static readonly string SpecifiedMethodIndexNoExplicitParametersNoImplicitThis = @" +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +readonly record struct NoCasting {} +partial interface INativeAPI : IUnmanagedInterfaceType +{ + static NoCasting IUnmanagedInterfaceType.TypeKey => default; + [VirtualMethodIndex(0, ImplicitThisParameter = false)] + void Method(); +}" + NativeInterfaceUsage(); + + public static readonly string SpecifiedMethodIndexNoExplicitParametersCallConvWithCallingConventions = @" +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +readonly record struct NoCasting {} +partial interface INativeAPI : IUnmanagedInterfaceType +{ + static NoCasting IUnmanagedInterfaceType.TypeKey => default; + + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })] + [VirtualMethodIndex(0)] + void Method(); + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl), typeof(CallConvMemberFunction) })] + [VirtualMethodIndex(1)] + void Method1(); + + [SuppressGCTransition] + [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl), typeof(CallConvMemberFunction) })] + [VirtualMethodIndex(2)] + void Method2(); + + [SuppressGCTransition] + [UnmanagedCallConv] + [VirtualMethodIndex(3)] + void Method3(); + + [SuppressGCTransition] + [VirtualMethodIndex(4)] + void Method4(); +}" + NativeInterfaceUsage(); + public static string BasicParametersAndModifiers(string typeName, string preDeclaration = "") => $@" +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +{preDeclaration} + +[assembly:DisableRuntimeMarshalling] + +readonly record struct NoCasting {{}} +partial interface INativeAPI : IUnmanagedInterfaceType +{{ + static NoCasting IUnmanagedInterfaceType.TypeKey => default; + [VirtualMethodIndex(0)] + {typeName} Method({typeName} value, in {typeName} inValue, ref {typeName} refValue, out {typeName} outValue); +}}" + NativeInterfaceUsage(); + public static string BasicParametersAndModifiers() => BasicParametersAndModifiers(typeof(T).FullName!); + public static string BasicParametersAndModifiersNoRef(string typeName, string preDeclaration = "") => $@" +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +{preDeclaration} + +[assembly:DisableRuntimeMarshalling] + +readonly record struct NoCasting {{}} +partial interface INativeAPI : IUnmanagedInterfaceType +{{ + static NoCasting IUnmanagedInterfaceType.TypeKey => default; + [VirtualMethodIndex(0)] + {typeName} Method({typeName} value, in {typeName} inValue, out {typeName} outValue); +}}" + NativeInterfaceUsage(); + public static string BasicParametersAndModifiersNoImplicitThis(string typeName) => $@" +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +readonly record struct NoCasting {{}} +partial interface INativeAPI : IUnmanagedInterfaceType +{{ + static NoCasting IUnmanagedInterfaceType.TypeKey => default; + [VirtualMethodIndex(0, ImplicitThisParameter = false)] + {typeName} Method({typeName} value, in {typeName} inValue, ref {typeName} refValue, out {typeName} outValue); +}}" + NativeInterfaceUsage(); + + public static string BasicParametersAndModifiersNoImplicitThis() => BasicParametersAndModifiersNoImplicitThis(typeof(T).FullName!); + + public static string BasicParameterByValue(string typeName, string preDeclaration = "") => $@" +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +{preDeclaration} + +readonly record struct NoCasting {{}} +partial interface INativeAPI : IUnmanagedInterfaceType +{{ + static NoCasting IUnmanagedInterfaceType.TypeKey => default; + [VirtualMethodIndex(0, ImplicitThisParameter = false)] + void Method({typeName} value); +}}" + NativeInterfaceUsage(); + public static string BasicParameterWithByRefModifier(string modifier, string typeName, string preDeclaration = "") => $@" +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +{preDeclaration} + +[assembly:DisableRuntimeMarshalling] + +readonly record struct NoCasting {{}} +partial interface INativeAPI : IUnmanagedInterfaceType +{{ + static NoCasting IUnmanagedInterfaceType.TypeKey => default; + [VirtualMethodIndex(0, ImplicitThisParameter = false)] + void Method({modifier} {typeName} value); +}}" + NativeInterfaceUsage(); + public static string BasicReturnType(string typeName, string preDeclaration = "") => $@" +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +{preDeclaration} + +readonly record struct NoCasting {{}} +partial interface INativeAPI : IUnmanagedInterfaceType +{{ + static NoCasting IUnmanagedInterfaceType.TypeKey => default; + [VirtualMethodIndex(0, ImplicitThisParameter = false)] + {typeName} Method(); +}}" + NativeInterfaceUsage(); + public static string MarshalUsingParametersAndModifiers(string typeName, string marshallerTypeName, string preDeclaration = "") => $@" +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +{preDeclaration} + +readonly record struct NoCasting {{}} +partial interface INativeAPI : IUnmanagedInterfaceType +{{ + static NoCasting IUnmanagedInterfaceType.TypeKey => default; + [VirtualMethodIndex(0)] + [return: MarshalUsing(typeof({marshallerTypeName}))] + {typeName} Method( + [MarshalUsing(typeof({marshallerTypeName}))] {typeName} p, + [MarshalUsing(typeof({marshallerTypeName}))] in {typeName} pIn, + [MarshalUsing(typeof({marshallerTypeName}))] ref {typeName} pRef, + [MarshalUsing(typeof({marshallerTypeName}))] out {typeName} pOut); +}}" + NativeInterfaceUsage(); + public static string MarshalUsingCollectionCountInfoParametersAndModifiers() => MarshalUsingCollectionCountInfoParametersAndModifiers(typeof(T).ToString()); + public static string MarshalUsingCollectionCountInfoParametersAndModifiers(string collectionType) => $@" +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +[assembly:DisableRuntimeMarshalling] + +readonly record struct NoCasting {{}} +partial interface INativeAPI : IUnmanagedInterfaceType +{{ + static NoCasting IUnmanagedInterfaceType.TypeKey => default; + [VirtualMethodIndex(0)] + [return:MarshalUsing(ConstantElementCount=10)] + {collectionType} Method( + {collectionType} p, + in {collectionType} pIn, + int pRefSize, + [MarshalUsing(CountElementName = ""pRefSize"")] ref {collectionType} pRef, + [MarshalUsing(CountElementName = ""pOutSize"")] out {collectionType} pOut, + out int pOutSize); +}}" + NativeInterfaceUsage(); + public static string MarshalUsingCollectionParametersAndModifiers(string collectionType, string marshallerType) => $@" +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +[assembly:DisableRuntimeMarshalling] + +readonly record struct NoCasting {{}} +partial interface INativeAPI : IUnmanagedInterfaceType +{{ + static NoCasting IUnmanagedInterfaceType.TypeKey => default; + [VirtualMethodIndex(0)] + [return:MarshalUsing(typeof({marshallerType}), ConstantElementCount=10)] + {collectionType} Method( + [MarshalUsing(typeof({marshallerType}))] {collectionType} p, + [MarshalUsing(typeof({marshallerType}))] in {collectionType} pIn, + int pRefSize, + [MarshalUsing(typeof({marshallerType}), CountElementName = ""pRefSize"")] ref {collectionType} pRef, + [MarshalUsing(typeof({marshallerType}), CountElementName = ""pOutSize"")] out {collectionType} pOut, + out int pOutSize + ); +}}" + NativeInterfaceUsage(); + public static string MarshalUsingCollectionReturnValueLength(string collectionType, string marshallerType) => $@" +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +[assembly:DisableRuntimeMarshalling] + +readonly record struct NoCasting {{}} +partial interface INativeAPI : IUnmanagedInterfaceType +{{ + static NoCasting IUnmanagedInterfaceType.TypeKey => default; + [VirtualMethodIndex(0)] + int Method( + [MarshalUsing(typeof({marshallerType}), CountElementName = MarshalUsingAttribute.ReturnsCountValue)] out {collectionType} pOut + ); +}}" + NativeInterfaceUsage(); + + public static string MarshalUsingCollectionOutConstantLength(string collectionType, string predeclaration = "") => $@" +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +{predeclaration} + +[assembly:DisableRuntimeMarshalling] + +readonly record struct NoCasting {{}} +partial interface INativeAPI : IUnmanagedInterfaceType +{{ + static NoCasting IUnmanagedInterfaceType.TypeKey => default; + [VirtualMethodIndex(0)] + int Method( + [MarshalUsing(ConstantElementCount = 10)] out {collectionType} pOut + ); +}} +"; + public static string MarshalUsingCollectionReturnConstantLength(string collectionType, string predeclaration = "") => $@" +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +{predeclaration} + +[assembly:DisableRuntimeMarshalling] + +readonly record struct NoCasting {{}} +partial interface INativeAPI : IUnmanagedInterfaceType +{{ + static NoCasting IUnmanagedInterfaceType.TypeKey => default; + [VirtualMethodIndex(0)] + [return:MarshalUsing(ConstantElementCount = 10)] + {collectionType} Method(); +}} +"; + public static string CustomElementMarshalling(string collectionType, string elementMarshaller, string predeclaration = "") => $@" +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; +{predeclaration} + +[assembly:DisableRuntimeMarshalling] + +readonly record struct NoCasting {{}} +partial interface INativeAPI : IUnmanagedInterfaceType +{{ + static NoCasting IUnmanagedInterfaceType.TypeKey => default; + [VirtualMethodIndex(0)] + [return:MarshalUsing(ConstantElementCount=10)] + [return:MarshalUsing(typeof({elementMarshaller}), ElementIndirectionDepth = 1)] + TestCollection Method( + [MarshalUsing(typeof({elementMarshaller}), ElementIndirectionDepth = 1)] {collectionType} p, + [MarshalUsing(typeof({elementMarshaller}), ElementIndirectionDepth = 1)] in {collectionType} pIn, + int pRefSize, + [MarshalUsing(CountElementName = ""pRefSize""), MarshalUsing(typeof({elementMarshaller}), ElementIndirectionDepth = 1)] ref {collectionType} pRef, + [MarshalUsing(CountElementName = ""pOutSize"")][MarshalUsing(typeof({elementMarshaller}), ElementIndirectionDepth = 1)] out {collectionType} pOut, + out int pOutSize + ); +}} +"; + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComInterfaceGenerator.Unit.Tests.csproj b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComInterfaceGenerator.Unit.Tests.csproj new file mode 100644 index 0000000000000..1fd768c257647 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/ComInterfaceGenerator.Unit.Tests.csproj @@ -0,0 +1,38 @@ + + + + $(NetCoreAppCurrent) + false + Preview + enable + true + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs new file mode 100644 index 0000000000000..65ac54d8cc64c --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Compiles.cs @@ -0,0 +1,261 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.Interop.UnitTests; +using Xunit; + +namespace ComInterfaceGenerator.Unit.Tests +{ + public class Compiles + { + private static string ID( + [CallerLineNumber] int lineNumber = 0, + [CallerFilePath] string? filePath = null) + => TestUtils.GetFileLineName(lineNumber, filePath); + + public static IEnumerable CodeSnippetsToCompile() + { + yield return new[] { ID(), CodeSnippets.SpecifiedMethodIndexNoExplicitParameters }; + yield return new[] { ID(), CodeSnippets.SpecifiedMethodIndexNoExplicitParametersNoImplicitThis }; + yield return new[] { ID(), CodeSnippets.SpecifiedMethodIndexNoExplicitParametersCallConvWithCallingConventions }; + + // Basic marshalling validation + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiersNoImplicitThis() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiersNoImplicitThis() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiersNoImplicitThis() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiersNoImplicitThis() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiersNoImplicitThis() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiersNoImplicitThis() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiersNoImplicitThis() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiersNoImplicitThis() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiersNoImplicitThis() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiersNoImplicitThis() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiersNoImplicitThis() }; + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiersNoImplicitThis() }; + + // Custom type marshalling + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateless.ParametersAndModifiers }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateless.MarshalUsingParametersAndModifiers }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateless.NativeToManagedOnlyOutParameter }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateless.NativeToManagedFinallyOnlyOutParameter }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateless.NativeToManagedOnlyReturnValue }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateless.NativeToManagedFinallyOnlyReturnValue }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateless.ByValueInParameter }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateless.PinByValueInParameter }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateless.StackallocByValueInParameter }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateless.RefParameter }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateless.StackallocParametersAndModifiersNoRef }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateless.OptionalStackallocParametersAndModifiers }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateless.DefaultModeByValueInParameter }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateless.DefaultModeReturnValue }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateful.ParametersAndModifiers }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateful.ParametersAndModifiersWithFree }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateful.ParametersAndModifiersWithOnInvoked }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateful.MarshalUsingParametersAndModifiers }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateful.NativeToManagedOnlyOutParameter }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateful.NativeToManagedFinallyOnlyOutParameter }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateful.NativeToManagedOnlyReturnValue }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateful.NativeToManagedFinallyOnlyReturnValue }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateful.ByValueInParameter }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateful.StackallocByValueInParameter }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateful.PinByValueInParameter }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateful.MarshallerPinByValueInParameter }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateful.RefParameter }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateful.StackallocParametersAndModifiersNoRef }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateful.OptionalStackallocParametersAndModifiers }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateful.DefaultModeByValueInParameter }; + yield return new[] { ID(), CustomStructMarshallingCodeSnippets.Stateful.DefaultModeReturnValue }; + + // SafeHandles + yield return new[] { ID(), CodeSnippets.BasicParametersAndModifiers("Microsoft.Win32.SafeHandles.SafeFileHandle") }; + } + + public static IEnumerable CustomCollections() + { + // Custom collection marshalling + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueCallerAllocatedBuffer() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.ByValueWithStaticPinning() }; + yield return new[] { ID(), CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), CodeSnippets.MarshalUsingCollectionCountInfoParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.CustomMarshallerReturnValueLength() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.NativeToManagedOnlyOutParameter() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.NativeToManagedOnlyReturnValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.NestedMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.NonBlittableElementByValue }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.NonBlittableElementParametersAndModifiers }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.NonBlittableElementNativeToManagedOnlyOutParameter }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.NonBlittableElementNativeToManagedOnlyReturnValue }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateless.CustomElementMarshalling }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.DefaultMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.CustomMarshallerParametersAndModifiers() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.CustomMarshallerReturnValueLength() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.NativeToManagedOnlyOutParameter() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.NativeToManagedOnlyReturnValue() }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.NonBlittableElementByValue }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.NonBlittableElementParametersAndModifiers }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.NonBlittableElementNativeToManagedOnlyOutParameter }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.NonBlittableElementNativeToManagedOnlyReturnValue }; + yield return new[] { ID(), CustomCollectionMarshallingCodeSnippets.Stateful.CustomElementMarshalling }; + } + + [Theory] + [MemberData(nameof(CodeSnippetsToCompile))] + [MemberData(nameof(CustomCollections))] + public async Task ValidateVTableIndexSnippets(string id, string source) + { + _ = id; + Compilation comp = await TestUtils.CreateCompilation(source); + // Allow the Native nested type name to be missing in the pre-source-generator compilation + // We allow duplicate usings here since some of the shared snippets add a using for System.Runtime.InteropServices.Marshalling when we already have one in our base snippets. + TestUtils.AssertPreSourceGeneratorCompilation(comp, "CS0426", "CS0105"); + + var newComp = TestUtils.RunGenerators(comp, out var generatorDiags, new Microsoft.Interop.VtableIndexStubGenerator()); + Assert.Empty(generatorDiags); + + TestUtils.AssertPostSourceGeneratorCompilation(newComp, "CS0105"); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Directory.Build.props b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Directory.Build.props new file mode 100644 index 0000000000000..fa9c3a4001db5 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/Directory.Build.props @@ -0,0 +1,7 @@ + + + + + true + + diff --git a/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/NativeInterfaceShape.cs b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/NativeInterfaceShape.cs new file mode 100644 index 0000000000000..26305c41b2276 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/NativeInterfaceShape.cs @@ -0,0 +1,102 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Metadata; +using System.Text; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Operations; +using Microsoft.Interop.UnitTests; +using Xunit; + +namespace ComInterfaceGenerator.Unit.Tests +{ + public class NativeInterfaceShape + { + [Fact] + public async Task NativeInterfaceNestedInUserInterface() + { + string source = @" +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +readonly record struct NoCasting {} +partial interface INativeAPI +{ + public static readonly NoCasting TypeKey = default; + [VirtualMethodIndex(0)] + void Method(); +}"; + Compilation comp = await TestUtils.CreateCompilation(source); + // Allow the Native nested type name to be missing in the pre-source-generator compilation + TestUtils.AssertPreSourceGeneratorCompilation(comp); + + var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator()); + + INamedTypeSymbol? userDefinedInterface = newComp.Assembly.GetTypeByMetadataName("INativeAPI"); + Assert.NotNull(userDefinedInterface); + + Assert.Single(userDefinedInterface.GetTypeMembers("Native")); + } + + [Fact] + public async Task NativeInterfaceInheritsFromUserInterface() + { + string source = @" +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +readonly record struct NoCasting {} +partial interface INativeAPI +{ + public static readonly NoCasting TypeKey = default; + [VirtualMethodIndex(0)] + void Method(); +}"; + Compilation comp = await TestUtils.CreateCompilation(source); + // Allow the Native nested type name to be missing in the pre-source-generator compilation + TestUtils.AssertPreSourceGeneratorCompilation(comp); + + var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator()); + + INamedTypeSymbol? userDefinedInterface = newComp.Assembly.GetTypeByMetadataName("INativeAPI"); + Assert.NotNull(userDefinedInterface); + + Assert.Equal(userDefinedInterface, Assert.Single(Assert.Single(userDefinedInterface.GetTypeMembers("Native")).Interfaces), SymbolEqualityComparer.Default); + } + + [Fact] + public async Task NativeInterfaceHasDynamicInterfaceCastableImplementationAttribute() + { + string source = @" +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Marshalling; + +readonly record struct NoCasting {} +partial interface INativeAPI +{ + public static readonly NoCasting TypeKey = default; + [VirtualMethodIndex(0)] + void Method(); +}"; + Compilation comp = await TestUtils.CreateCompilation(source); + // Allow the Native nested type name to be missing in the pre-source-generator compilation + TestUtils.AssertPreSourceGeneratorCompilation(comp); + + var newComp = TestUtils.RunGenerators(comp, out _, new Microsoft.Interop.VtableIndexStubGenerator()); + + INamedTypeSymbol? userDefinedInterface = newComp.Assembly.GetTypeByMetadataName("INativeAPI"); + Assert.NotNull(userDefinedInterface); + + INamedTypeSymbol dynamicInterfaceCastableImplementationAttribute = newComp.GetTypeByMetadataName("System.Runtime.InteropServices.DynamicInterfaceCastableImplementationAttribute")!; + + Assert.Contains( + dynamicInterfaceCastableImplementationAttribute, + Assert.Single(userDefinedInterface.GetTypeMembers("Native")).GetAttributes().Select(attr => attr.AttributeClass), + SymbolEqualityComparer.Default); + } + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/Common/MarshalDirection.cs b/src/libraries/System.Runtime.InteropServices/tests/Common/MarshalDirection.cs new file mode 100644 index 0000000000000..131506e7cc7f6 --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/Common/MarshalDirection.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if ANCILLARY_INTEROP +namespace System.Runtime.InteropServices.Marshalling +#else +namespace Microsoft.Interop +#endif +{ + public enum MarshalDirection + { + ManagedToUnmanaged = 0, + UnmanagedToManaged = 1, + Bidirectional = 2 + } +} diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs index c990cef0461f5..51a0858394400 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.UnitTests/IncrementalGenerationTests.cs @@ -4,6 +4,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Text; +using Microsoft.Interop.UnitTests; using System; using System.Collections.Generic; using System.Linq; @@ -12,7 +13,6 @@ using System.Text; using System.Threading.Tasks; using Xunit; -using Microsoft.Interop.UnitTests; using static Microsoft.Interop.LibraryImportGenerator; namespace LibraryImportGenerator.UnitTests diff --git a/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/VirtualMethodTables.cs b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/VirtualMethodTables.cs new file mode 100644 index 0000000000000..ac75c735f7daa --- /dev/null +++ b/src/libraries/System.Runtime.InteropServices/tests/TestAssets/NativeExports/VirtualMethodTables.cs @@ -0,0 +1,99 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace NativeExports +{ + public unsafe static class VirtualMethodTables + { + struct StaticFunctionTable + { + public delegate* unmanaged Add; + public delegate* unmanaged Multiply; + } + + [UnmanagedCallersOnly] + private static int Add(int x, int y) => x + y; + + [UnmanagedCallersOnly] + private static int Multiply(int x, int y) => x * y; + + private static readonly StaticFunctionTable* StaticTable; + + static VirtualMethodTables() + { + StaticTable = (StaticFunctionTable*)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(VirtualMethodTables), sizeof(StaticFunctionTable)); + + StaticTable->Add = &Add; + StaticTable->Multiply = &Multiply; + } + + [UnmanagedCallersOnly(EntryPoint = "get_static_function_table")] + public static void* GetStaticFunctionTable() + { + return StaticTable; + } + + public struct NativeObject + { + private struct VirtualFunctionTable + { + public delegate* unmanaged getData; + public delegate* unmanaged setData; + } + + static NativeObject() + { + VTablePointer = (VirtualFunctionTable*)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(NativeObject), sizeof(VirtualFunctionTable)); + VTablePointer->getData = &GetData; + VTablePointer->setData = &SetData; + } + + private static readonly VirtualFunctionTable* VTablePointer; + + private readonly VirtualFunctionTable* vtable = VTablePointer; + + public NativeObject() + { + } + + public int Data { get; set; } = 0; + + [UnmanagedCallersOnly] + private static int GetData(NativeObject* obj) + { + return obj->Data; + } + + [UnmanagedCallersOnly] + private static void SetData(NativeObject* obj, int value) + { + obj->Data = value; + } + } + + [UnmanagedCallersOnly(EntryPoint = "new_native_object")] + [DNNE.C99DeclCode("struct NativeObject;")] + [return: DNNE.C99Type("struct NativeObject*")] + public static NativeObject* NewNativeObject() + { + NativeObject* memory = (NativeObject*)NativeMemory.Alloc((nuint)sizeof(NativeObject)); + *memory = new NativeObject(); + return memory; + } + + [UnmanagedCallersOnly(EntryPoint = "delete_native_object")] + [DNNE.C99DeclCode("struct NativeObject;")] + public static void DeleteNativeObject([DNNE.C99Type("struct NativeObject*")] NativeObject* obj) + { + NativeMemory.Free(obj); + } + } +} diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index 157b699d52a0b..e536a36f52871 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -82,13 +82,15 @@ - - + + + + @@ -101,31 +103,38 @@ + + + + + - + + + @@ -133,6 +142,7 @@ + @@ -271,7 +281,7 @@ - @@ -279,7 +289,7 @@ - + @@ -416,7 +426,7 @@ - +