Freigeben über


Erstellen von Prototypen in verwaltetem Code

In diesem Thema wird beschrieben, wie Sie auf nicht verwaltete Funktionen zugreifen und mehrere Attributfelder einführen, die die Methodendefinition in verwaltetem Code kommentieren. Beispiele, die veranschaulichen, wie .NET-basierte Deklarationen erstellt werden, die mit Platform Invoke verwendet werden sollen, finden Sie unter Marshalling Data with Platform Invoke.

Bevor Sie über verwalteten Code auf eine nicht verwaltete DLL-Funktion zugreifen können, müssen Sie den Namen der Funktion und den Namen der DLL kennen, die sie exportiert. Mit diesen Informationen können Sie beginnen, die verwaltete Definition für eine nicht verwaltete Funktion zu schreiben, die in einer DLL implementiert ist. Darüber hinaus können Sie die Art und Weise anpassen, in der die Funktion durch Plattformaufrufe erstellt wird und die Daten zur und von der Funktion gemarshallt werden.

Hinweis

Mit Windows-API-Funktionen, die eine Zeichenfolge zuweisen, können Sie diese mithilfe einer Methode wie LocalFree freigeben. Der Plattform-Aufruf behandelt solche Parameter unterschiedlich. Verwenden Sie bei Plattformaufrufen einen Parameter vom Typ IntPtr statt einem vom Typ String. Verwenden Sie Methoden, die von der System.Runtime.InteropServices.Marshal Klasse bereitgestellt werden, um den Typ manuell in eine Zeichenfolge zu konvertieren und manuell freizugeben.

Deklarationsgrundlagen

Verwaltete Definitionen für nicht verwaltete Funktionen sind sprachabhängig, wie Sie in den folgenden Beispielen sehen können. Ausführlichere Codebeispiele finden Sie unter Platform Invoke Examples.

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

Um die Felder DllImportAttribute.BestFitMapping, DllImportAttribute.CallingConvention, DllImportAttribute.ExactSpelling, DllImportAttribute.PreserveSig, DllImportAttribute.SetLastError oder DllImportAttribute.ThrowOnUnmappableChar auf eine Visual Basic-Deklaration anzuwenden, verwenden Sie das DllImportAttribute-Attribut anstelle der Declare-Anweisung.

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);

Anpassen der Definition

Unabhängig davon, ob Sie sie explizit festlegen, definieren Attributfelder das Verhalten von verwaltetem Code. Der Plattformaufruf funktioniert gemäß den Standardwerten, die für verschiedene Felder festgelegt sind, die als Metadaten in einer Assembly vorhanden sind. Sie können dieses Standardverhalten ändern, indem Sie die Werte eines oder mehrerer Felder anpassen. In vielen Fällen verwenden Sie den DllImportAttribute Wert, um einen Wert festzulegen.

In der folgenden Tabelle sind die vollständigen Attributfelder aufgeführt, die sich auf den Plattform-Aufruf beziehen. Für jedes Feld enthält die Tabelle den Standardwert und einen Link zu Informationen zur Verwendung dieser Felder, um nicht verwaltete DLL-Funktionen zu definieren.

Feld BESCHREIBUNG
BestFitMapping Aktiviert oder deaktiviert die Zuordnung mit ähnlichen Zeichen.
CallingConvention Gibt die Aufrufkonvention an, die beim Übergeben von Methodenargumenten verwendet werden soll. Der Standardwert ist WinAPI, was dem __stdcall für Intel-basierte 32-Bit-Plattformen entspricht.
CharSet Steuert die Namenszerlegung und die Art und Weise, in der Zeichenfolgenargumente an die Funktion gemarshallt werden sollen Der Standardwert lautet CharSet.Ansi.
EntryPoint Gibt den DLL-Eingangspunkt an, der aufgerufen werden soll.
ExactSpelling Steuert, ob ein Einstiegspunkt geändert werden soll, um dem Zeichensatz zu entsprechen. Der Standardwert variiert je nach Programmiersprache.
PreserveSig Steuert, ob die Signatur der verwalteten Methode in eine nicht verwaltete Signatur umgewandelt werden soll, die ein HRESULT zurückgibt und über ein zusätzliches [out, retval]-Argument für den Rückgabewert verfügt.

Der Standardwert ist true (die Signatur sollte nicht transformiert werden).
SetLastError Ermöglicht dem Aufrufer die Verwendung der Marshal.GetLastWin32Error API-Funktion, um zu bestimmen, ob beim Ausführen der Methode ein Fehler aufgetreten ist. In Visual Basic lautet trueder Standardwert ; in C# und C++, der Standardwert ist false.
ThrowOnUnmappableChar Steuert das Auslösen einer Ausnahme bei einem nicht zuzuordnenden Unicode-Zeichen, das in ein ANSI-Zeichen ("?") konvertiert wird.

Ausführliche Referenzinformationen finden Sie unter DllImportAttribute.

Überlegungen zur Plattformaufrufsicherheit

Die Member Assert, Deny und PermitOnly der SecurityAction-Enumeration werden als stack walk modifier (Stackwalkmodifizierer) bezeichnet. Diese Member werden ignoriert, wenn sie als deklarative Attribute für Deklarationen von Plattformaufrufen und COM-IDL-Anweisungen (Interface Definition Language) verwendet werden.

Beispiele für Plattformaufrufe

Die Beispiele zum Plattformaufruf in diesem Abschnitt veranschaulichen die Verwendung des RegistryPermission-Attributs mit den Stapelmodifizierern.

Im folgenden Beispiel werden die SecurityAction, Assert, Deny und PermitOnly-Modifizierer ignoriert.

[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();  

Der Demand Modifizierer im folgenden Beispiel wird jedoch akzeptiert.

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

SecurityAction Modifizierer funktionieren ordnungsgemäß, wenn sie in einer Klasse platziert werden, die den Aufruf der Plattform enthält (umschließt).

      [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-Modifizierer funktionieren auch in einem geschachtelten Szenario ordnungsgemäß, in dem sie im Aufrufer des Plattformaufrufs positioniert werden:

      {  
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();  
    }  
}  

Beispiele zu COM-Interop

Die COM-Interop-Beispiele in diesem Abschnitt veranschaulichen die Verwendung des RegistryPermission-Attributs mit den Stack-Walk-Modifizierern.

Die folgenden COM-Interop-Schnittstellendeklarationen ignorieren die Modifizierer Assert, Deny und PermitOnly, ähnlich wie die Plattformaufrufe-Beispiele im vorherigen Abschnitt.

[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();  
}  

Darüber hinaus wird der Demand Modifizierer in COM-Interopschnittstellendeklarationsszenarien nicht akzeptiert, wie im folgenden Beispiel gezeigt.

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

Siehe auch