Share via


Brongeneratie voor ComWrappers

.NET 8 introduceert een brongenerator die een implementatie van de ComWrappers-API voor u maakt. De generator herkent de GeneratedComInterfaceAttribute.

Het ingebouwde .NET Runtime-systeem (niet door bron gegenereerd), Windows-only, COM-interop-systeem genereert een IL-stub( een stroom IL-instructies die JIT-ed is) tijdens runtime om de overgang van beheerde code naar COM te vergemakkelijken en vice versa. Omdat deze IL-stub tijdens runtime wordt gegenereerd, is deze niet compatibel met NativeAOT en IL-bijsnijding. Stub generatie tijdens runtime kan ook het diagnosticeren van marshalling problemen moeilijk maken.

Ingebouwde interoperabiliteit maakt gebruik van kenmerken zoals ComImport of DllImport, die afhankelijk zijn van het genereren van code tijdens runtime. In de volgende code ziet u een voorbeeld hiervan:

[ComImport]
interface IFoo
{
    void Method(int i);
}

[DllImport("MyComObjectProvider.dll")]
static nint GetPointerToComInterface();

[DllImport("MyComObjectProvider.dll")]
static void GivePointerToComInterface(nint comObject);

// Use the system to create a Runtime Callable Wrapper to use in managed code
nint ptr = GetPointerToComInterface();
IFoo foo = (IFoo)Marshal.GetObjectForIUnknown(ptr);
foo.Method(0);
...
// Use the system to create a COM Callable Wrapper to pass to unmanaged code
IFoo foo = GetManagedIFoo();
nint ptr = Marshal.GetIUnknownForObject(foo);
GivePointerToComInterface(ptr);

De ComWrappers API maakt interactie mogelijk met COM in C# zonder gebruik te maken van het ingebouwde COM-systeem, maar vereist aanzienlijke standaard en handgeschreven onveilige code. De COM-interfacegenerator automatiseert dit proces en maakt ComWrappers het net zo eenvoudig als ingebouwde COM, maar levert het op een inkortbare en AOT-vriendelijke manier.

Basaal gebruik

Als u de COM-interfacegenerator wilt gebruiken, voegt u de GeneratedComInterfaceAttribute en GuidAttribute kenmerken toe aan de interfacedefinitie waaruit u wilt importeren of beschikbaar wilt maken voor COM. Het type moet worden gemarkeerd partial en moet de gegenereerde code of public zichtbaarheid hebben internal om er toegang toe te krijgen.

[GeneratedComInterface]
[Guid("3faca0d2-e7f1-4e9c-82a6-404fd6e0aab8")]
internal partial interface IFoo
{
    void Method(int i);
}

Als u vervolgens een klasse beschikbaar wilt maken die een interface implementeert op COM, voegt u de GeneratedComClassAttribute klasse toe aan de implementatieklasse. Deze klasse moet ook en partial of internalpublic.

[GeneratedComClass]
internal partial class Foo : IFoo
{
    public void Method(int i)
    {
        // Do things
    }
}

Tijdens het compileren maakt de generator een implementatie van de ComWrappers-API en kunt u het StrategyBasedComWrappers type of een aangepast afgeleid type gebruiken om de COM-interface te gebruiken of beschikbaar te maken.

[LibraryImport("MyComObjectProvider.dll")]
static nint GetPointerToComInterface();

[LibraryImport("MyComObjectProvider.dll")]
static void GivePointerToComInterface(nint comObject);

// Use the ComWrappers API to create a Runtime Callable Wrapper to use in managed code
ComWrappers cw = new StrategyBasedComWrappers();
nint ptr = GetPointerToComInterface();
IFoo foo = (IFoo)cw.GetOrCreateObjectForComInterface(ptr);
foo.Method(0);
...
// Use the system to create a COM Callable Wrapper to pass to unmanaged code
ComWrappers cw = new StrategyBasedComWrappers();
Foo foo = new();
nint ptr = cw.GetOrCreateComInterfaceForObject(foo);
GivePointerToComInterface(ptr);

Marshalling aanpassen

De COM-interfacegenerator respecteert het MarshalUsingAttribute kenmerk en sommige gebruiksrechten van het MarshalAsAttribute kenmerk om marshalling van parameters aan te passen. Zie voor meer informatie hoe u door de bron gegenereerde marshalling kunt aanpassen met het MarshalUsing kenmerk en het aanpassen van parameter marshalling met het MarshalAs kenmerk. De GeneratedComInterfaceAttribute.StringMarshalling eigenschappen zijn GeneratedComInterfaceAttribute.StringMarshallingCustomType van toepassing op alle parameters en retourtypen in string de interface als ze geen andere marshallingkenmerken hebben.

Impliciete HRESULTs en PreserveSig

COM-methoden in C# hebben een andere handtekening dan de systeemeigen methoden. Standaard COM heeft een retourtype, een geheel getal van HRESULT4 byte dat fout- en successtatussen vertegenwoordigt. Deze HRESULT retourwaarde is standaard verborgen in de C#-handtekening en geconverteerd naar een uitzondering wanneer een foutwaarde wordt geretourneerd. De laatste out-parameter van de systeemeigen COM-handtekening kan eventueel worden geconverteerd naar de return in de C#-handtekening.

In de volgende fragmenten worden bijvoorbeeld C#-methodehandtekeningen en de bijbehorende systeemeigen handtekening weergegeven die door de generator wordt afgeleid.

void Method1(int i);

int Method2(float i);
HRESULT Method1(int i);

HRESULT Method2(float i, _Out_ int* returnValue);

Als u de HRESULT uzelf wilt afhandelen, kunt u de PreserveSigAttribute methode gebruiken om aan te geven dat de generator deze transformatie niet mag uitvoeren. De volgende codefragmenten laten zien welke systeemeigen handtekening de generator verwacht wanneer [PreserveSig] deze wordt toegepast. COM-methoden moeten worden geretourneerd HRESULT, dus de retourwaarde van een methode met PreserveSig moet zijn int.

[PreserveSig]
int Method1(int i, out int j);

[PreserveSig]
int Method2(float i);
HRESULT Method1(int i, int* j);

HRESULT Method2(float i);

Zie Impliciete vertalingen van methodehandtekening in .NET-interop voor meer informatie

Incompatibiliteit en verschillen in ingebouwde COM

IUnknown Alleen

De enige ondersteunde interfacebasis is IUnknown. Interfaces met een InterfaceTypeAttribute andere waarde dan InterfaceIsIUnknown worden niet ondersteund in COM die door de bron wordt gegenereerd. Alle interfaces zonder een InterfaceTypeAttribute worden ervan uitgegaan dat ze worden afgeleid van IUnknown. Dit verschilt van ingebouwde COM waar de standaardwaarde is InterfaceIsDual.

Standaardinstellingen en ondersteuning van marshalling

Door de bron gegenereerde COM heeft een aantal verschillende standaard marshallinggedrag van ingebouwde COM.

  • In het ingebouwde COM-systeem hebben alle typen een impliciet [In] kenmerk, met uitzondering van matrices met belichte elementen, die impliciete [In, Out] kenmerken hebben. In bron gegenereerde COM hebben [In] alle typen, waaronder matrices van belichte elementen, semantiek.

  • [In] en [Out] kenmerken zijn alleen toegestaan voor matrices. Als [Out] of [In, Out] gedrag vereist is voor andere typen, gebruikt u de in en out parameteraanpassingen.

Afgeleide interfaces

Als u in het ingebouwde COM-systeem interfaces hebt die zijn afgeleid van andere COM-interfaces, moet u een schaduwmethode declareren voor elke basismethode op de basisinterfaces met het new trefwoord. Zie COM-interfaceovername en .NET voor meer informatie.

[ComImport]
[Guid("3faca0d2-e7f1-4e9c-82a6-404fd6e0aab8")]
interface IBase
{
    void Method1(int i);
    void Method2(float i);
}

[ComImport]
[Guid("3faca0d2-e7f1-4e9c-82a6-404fd6e0aab8")]
interface IDerived : IBase
{
    new void Method1(int i);
    new void Method2(float f);
    void Method3(long l);
    void Method4(double d);
}

De COM-interfacegenerator verwacht geen schaduw van basismethoden. Als u een methode wilt maken die van een andere methode overkomt, geeft u de basisinterface aan als een C#-basisinterface en voegt u de methoden van de afgeleide interface toe. Zie het ontwerpdocument voor meer informatie.

[GeneratedComInterface]
[Guid("3faca0d2-e7f1-4e9c-82a6-404fd6e0aab8")]
interface IBase
{
    void Method1(int i);
    void Method2(float i);
}

[GeneratedComInterface]
[Guid("3faca0d2-e7f1-4e9c-82a6-404fd6e0aab8")]
interface IDerived : IBase
{
    void Method3(long l);
    void Method4(double d);
}

Houd er rekening mee dat een interface met het GeneratedComInterface kenmerk slechts kan overnemen van één basisinterface die het GeneratedComInterface kenmerk heeft.

Marshal-API's

Sommige API's in Marshal zijn niet compatibel met door de bron gegenereerde COM. Vervang deze methoden door de bijbehorende methoden voor een ComWrappers implementatie.

Zie ook