Prototypen maken in beheerde code

In dit onderwerp wordt beschreven hoe u toegang krijgt tot niet-beheerde functies en een aantal kenmerkvelden introduceert die aantekeningen toevoegen aan de methodedefinitie in beheerde code. Voor voorbeelden die laten zien hoe u kunt bouwen. Declaraties op basis van NET die moeten worden gebruikt met platformaanroepen, zie Marshalling Data with Platform Invoke.

Voordat u toegang hebt tot een niet-beheerde DLL-functie vanuit beheerde code, moet u de naam van de functie en de naam van de DLL die deze exporteert, weten. Met deze informatie kunt u beginnen met het schrijven van de beheerde definitie voor een niet-beheerde functie die is geïmplementeerd in een DLL. Bovendien kunt u de manier aanpassen waarop het platform de functie- en marshals-gegevens naar en van de functie aanroept.

Notitie

Met Windows API-functies waarmee een tekenreeks wordt toegewezen, kunt u de tekenreeks vrijmaken met behulp van een methode zoals LocalFree. Platform roept dergelijke parameters anders aan. Voor aanroepen van platformaanroepen moet u de parameter een IntPtr type maken in plaats van een String type. Gebruik methoden die door de System.Runtime.InteropServices.Marshal klasse worden geleverd om het type handmatig te converteren naar een tekenreeks en deze handmatig vrij te maken.

Basisbeginselen van declaratie

Beheerde definities voor niet-beheerde functies zijn taalafhankelijk, zoals u kunt zien in de volgende voorbeelden. Zie Voorbeelden van platform invoke voor meer volledige codevoorbeelden.

Friend Class NativeMethods
    Friend Declare Auto Function MessageBox Lib "user32.dll" (
        ByVal hWnd As IntPtr,
        ByVal lpText As String,
        ByVal lpCaption As String,
        ByVal uType As UInteger) As Integer
End Class

Als u de DllImportAttribute.BestFitMappingvelden , DllImportAttribute.CallingConvention, DllImportAttribute.ExactSpellingof DllImportAttribute.SetLastErrorDllImportAttribute.PreserveSigDllImportAttribute.ThrowOnUnmappableChar velden wilt toepassen op een Visual Basic-declaratie, moet u het DllImportAttribute kenmerk gebruiken in plaats van de Declare instructie.

Imports System.Runtime.InteropServices

Friend Class NativeMethods
    <DllImport("user32.dll", CharSet:=CharSet.Auto)>
    Friend Shared Function MessageBox(
        ByVal hWnd As IntPtr,
        ByVal lpText As String,
        ByVal lpCaption As String,
        ByVal uType As UInteger) As Integer
    End Function
End Class
using System;
using System.Runtime.InteropServices;

internal static class NativeMethods
{
    [DllImport("user32.dll")]
    internal static extern int MessageBox(
        IntPtr hWnd, string lpText, string lpCaption, uint uType);
}
using namespace System;
using namespace System::Runtime::InteropServices;

[DllImport("user32.dll")]
extern "C" int MessageBox(
    IntPtr hWnd, String* lpText, String* lpCaption, unsigned int uType);

De definitie aanpassen

Of u deze nu expliciet instelt of niet, kenmerkvelden werken aan het definiëren van het gedrag van beheerde code. Het aanroepen van het platform werkt volgens de standaardwaarden die zijn ingesteld op verschillende velden die bestaan als metagegevens in een assembly. U kunt dit standaardgedrag wijzigen door de waarden van een of meer velden aan te passen. In veel gevallen gebruikt u de DllImportAttribute functie om een waarde in te stellen.

De volgende tabel bevat de volledige set kenmerkvelden die betrekking hebben op het aanroepen van het platform. Voor elk veld bevat de tabel de standaardwaarde en een koppeling naar informatie over het gebruik van deze velden om onbeheerde DLL-functies te definiëren.

Veld Beschrijving
BestFitMapping Hiermee schakelt u de best passende toewijzing in of uit.
CallingConvention Hiermee geeft u de aanroepconventie op die moet worden gebruikt bij het doorgeven van methodeargumenten. De standaardwaarde is WinAPI, die overeenkomt met __stdcall de 32-bits Intel-platforms.
CharSet Bepaalt naambeheer en de manier waarop tekenreeksargumenten moeten worden ge marshalld voor de functie. De standaardwaarde is CharSet.Ansi.
EntryPoint Hiermee geeft u het DLL-toegangspunt moet worden aangeroepen.
ExactSpelling Hiermee bepaalt u of een toegangspunt moet worden gewijzigd zodat deze overeenkomt met de tekenset. De standaardwaarde verschilt per programmeertaal.
PreserveSig Hiermee bepaalt u of de handtekening van de beheerde methode moet worden omgezet in een niet-beheerde handtekening die een HRESULT retourneert en een extra argument [out, retval] voor de retourwaarde heeft.

De standaardwaarde is true (de handtekening mag niet worden getransformeerd).
SetLastError Hiermee kan de aanroeper de Marshal.GetLastWin32Error API-functie gebruiken om te bepalen of er een fout is opgetreden tijdens het uitvoeren van de methode. In Visual Basic is truede standaardwaarde ; in C# en C++, de standaardwaarde is false.
ThrowOnUnmappableChar Besturingselementen voor het genereren van een uitzondering op een niet-toe te passen Unicode-teken dat wordt geconverteerd naar een ANSI -teken '?'.

Zie voor gedetailleerde naslaginformatie DllImportAttribute.

Beveiligingsoverwegingen voor platform aanroepen

De Assert, Denyen PermitOnly leden van de SecurityAction opsomming worden stack walk modifiers genoemd. Deze leden worden genegeerd als ze worden gebruikt als declaratieve kenmerken op platformaanroepen en IDL-instructies (COM Interface Definition Language).

Voorbeelden van het aanroepen van platformen

Het platform roept voorbeelden in deze sectie aan om het gebruik van het RegistryPermission kenmerk te illustreren met de stack walk-modifiers.

In het volgende voorbeeld worden de SecurityActionAssert, Denyen PermitOnly modifiers genegeerd.

[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
[RegistryPermission(SecurityAction.Assert, Unrestricted = true)]  
    private static extern bool CallRegistryPermissionAssert();  
  
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
[RegistryPermission(SecurityAction.Deny, Unrestricted = true)]  
    private static extern bool CallRegistryPermissionDeny();  
  
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
[RegistryPermission(SecurityAction.PermitOnly, Unrestricted = true)]  
    private static extern bool CallRegistryPermissionDeny();  

De Demand wijzigingsfunctie in het volgende voorbeeld wordt echter geaccepteerd.

[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
    private static extern bool CallRegistryPermissionDeny();  

SecurityAction modifiers werken correct als ze worden geplaatst op een klasse die (verpakt) het aanroepen van het platform bevat.

      [RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
public ref class PInvokeWrapper  
{  
public:  
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
    private static extern bool CallRegistryPermissionDeny();  
};  
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
class PInvokeWrapper  
{  
[DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
    private static extern bool CallRegistryPermissionDeny();  
}  

SecurityAction modifiers werken ook correct in een genest scenario waarin ze worden geplaatst op de aanroeper van het platform:

      {  
public ref class PInvokeWrapper  
public:  
    [DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
    private static extern bool CallRegistryPermissionDeny();  
  
    [RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
    public static bool CallRegistryPermission()  
    {  
     return CallRegistryPermissionInternal();  
    }  
};  
class PInvokeScenario  
{  
    [DllImport("MyClass.dll", EntryPoint = "CallRegistryPermission")]  
    private static extern bool CallRegistryPermissionInternal();  
  
    [RegistryPermission(SecurityAction.Assert, Unrestricted = true)]  
    public static bool CallRegistryPermission()  
    {  
     return CallRegistryPermissionInternal();  
    }  
}  

Voorbeelden van COM-interoperabiliteit

De COM-interoperabiliteitsvoorbeelden in deze sectie illustreren het gebruik van het RegistryPermission kenmerk met de stack walk-modifiers.

De volgende com-interop interfacedeclaraties negeren de Assert, Denyen PermitOnly modifiers, vergelijkbaar met het platform aanroepen voorbeelden in de vorige sectie.

[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]  
interface IAssertStubsItf  
{  
[RegistryPermission(SecurityAction.Assert, Unrestricted = true)]  
    bool CallRegistryPermission();  
[FileIOPermission(SecurityAction.Assert, Unrestricted = true)]  
    bool CallFileIoPermission();  
}  
  
[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]  
interface IDenyStubsItf  
{  
[RegistryPermission(SecurityAction.Deny, Unrestricted = true)]  
    bool CallRegistryPermission();  
[FileIOPermission(SecurityAction.Deny, Unrestricted = true)]  
    bool CallFileIoPermission();  
}  
  
[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]  
interface IAssertStubsItf  
{  
[RegistryPermission(SecurityAction.PermitOnly, Unrestricted = true)]  
    bool CallRegistryPermission();  
[FileIOPermission(SecurityAction.PermitOnly, Unrestricted = true)]  
    bool CallFileIoPermission();  
}  

Bovendien wordt de Demand wijzigingsfunctie niet geaccepteerd in com-interop interfacedeclaratiescenario's, zoals wordt weergegeven in het volgende voorbeeld.

[ComImport, Guid("12345678-43E6-43c9-9A13-47F40B338DE0")]  
interface IDemandStubsItf  
{  
[RegistryPermission(SecurityAction.Demand, Unrestricted = true)]  
    bool CallRegistryPermission();  
[FileIOPermission(SecurityAction.Demand, Unrestricted = true)]  
    bool CallFileIoPermission();  
}  

Zie ook