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 true de 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
, Deny
en 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
, Deny
en 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
, Deny
en 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();
}