Exemplarische Vorgehensweise: Aufrufen von Windows-APIs (Visual Basic)

Windows-APIs sind DLLs (Dynamic Link Libraries), die Teil des Windows-Betriebssystems sind. Sie werden verwendet, um Aufgaben auszuführen, wenn es schwierig ist, eigene gleichwertige Prozeduren zu schreiben. Windows bietet beispielsweise eine Funktion namens FlashWindowEx, mit der Sie die Titelleiste einer Anwendung abwechselnd hell und dunkel schattieren können.

Der Vorteil der Verwendung von Windows-APIs in Ihrem Code besteht darin, dass sie Entwicklungszeit einsparen können, da sie Dutzende von nützlichen Funktionen enthalten, die bereits geschrieben wurden und darauf warten, verwendet zu werden. Der Nachteil besteht darin, dass die Windows-APIs schwer zu handhaben sind und bei Problemen keine Nachsicht walten lassen.

Windows-APIs stellen eine besondere Kategorie von Interoperabilität dar. Windows-APIs verwenden keinen verwalteten Code, verfügen nicht über integrierte Typbibliotheken und verwenden Datentypen, die sich von denen unterscheiden, die mit Visual Studio verwendet werden. Aufgrund dieser Unterschiede und weil es sich bei Windows-APIs nicht um COM-Objekte handelt, wird Interoperabilität mit Windows-APIs und .NET Framework mit einem Plattformaufruf oder PInvoke durchgeführt. Der Plattformaufruf ist ein Dienst, der es verwaltetem Code ermöglicht, nicht verwaltete Funktionen aufzurufen, die in DLLs (Dynamic Link Library) implementiert sind. Weitere Informationen finden Sie unter Verwenden nicht verwalteter DLL-Funktionen. Sie können PInvoke in Visual Basic verwenden, indem Sie entweder die Declare-Anweisung verwenden oder das DllImport-Attribut auf eine leere Prozedur anwenden.

Windows-API-Aufrufe waren in der Vergangenheit ein wichtiger Bestandteil der Visual Basic-Programmierung, sind aber mit Visual Basic .NET nur selten erforderlich. Wenn möglich, sollten Sie verwalteten Code aus .NET Framework anstelle von Windows-API-Aufrufen verwenden, um Aufgaben auszuführen. Diese exemplarische Vorgehensweise enthält Informationen zu Situationen, in denen die Verwendung von Windows-APIs erforderlich ist.

Hinweis

Auf Ihrem Computer werden möglicherweise andere Namen oder Speicherorte für die Benutzeroberflächenelemente von Visual Studio angezeigt als die in den folgenden Anweisungen aufgeführten. Diese Elemente sind von der jeweiligen Visual Studio-Version und den verwendeten Einstellungen abhängig. Weitere Informationen finden Sie unter Personalisieren der IDE.

API-Aufrufe mithilfe von Declare

Die gängigste Methode zum Aufrufen von Windows-APIs ist die Verwendung der Declare-Anweisung.

So deklarieren Sie eine DLL-Prozedur

  1. Bestimmen Sie den Namen der Funktion, die Sie aufrufen möchten, sowie deren Argumente, Argumenttypen und Rückgabewert sowie den Namen und Speicherort der DLL, die sie enthält.

    Hinweis

    Vollständige Informationen zu den Windows-APIs finden Sie in der Win32 SDK-Dokumentation in der Windows-API des Platform SDK. Weitere Informationen zu den Konstanten, die von Windows-APIs verwendet werden, finden Sie in den Headerdateien wie „Windows.h“, die im Platform SDK enthalten sind.

  2. Öffnen Sie ein neues Windows-Anwendungsprojekt, indem Sie im Menü Datei auf Neu und dann auf Projekt klicken. Das Dialogfeld Neues Projekt wird angezeigt.

  3. Wählen Sie in der Liste der Visual Basic-Projektvorlagen die Option Windows-Anwendung aus. Das neue Projekt wird angezeigt.

  4. Fügen Sie die folgende Declare-Funktion entweder der Klasse oder dem Modul hinzu, in der bzw. dem Sie die DLL verwenden möchten:

    Declare Auto Function MBox Lib "user32.dll" Alias "MessageBox" (
        ByVal hWnd As Integer,
        ByVal txt As String,
        ByVal caption As String,
        ByVal Typ As Integer) As Integer
    

Teile der Declare-Anweisung

Die Declare-Anweisung schließt die folgenden Elemente ein.

Automatischer Modifizierer

Der Auto-Modifizierer weist die Laufzeit an, die Zeichenfolge basierend auf dem Methodennamen gemäß Common Language Runtime-Regeln (oder dem Aliasnamen, falls angegeben) zu konvertieren.

Bibliotheks- und Aliasschlüsselwörter

Der Name, der auf das Function-Schlüsselwort folgt, ist der Name, den Ihr Programm für den Zugriff auf die importierte Funktion verwendet. Er kann mit dem tatsächlichen Namen der Funktion identisch sein, die Sie aufrufen, oder Sie können einen beliebigen gültigen Prozedurnamen verwenden und dann das Alias-Schlüsselwort verwenden, um den tatsächlichen Namen der Funktion anzugeben, die Sie aufrufen.

Geben Sie das Lib-Schlüsselwort an, gefolgt vom Namen und Speicherort der DLL, die die Funktion enthält, die Sie aufrufen. Sie müssen den Pfad für Dateien in den Windows-Systemverzeichnissen nicht angeben.

Verwenden Sie das Alias-Schlüsselwort, wenn der Name der aufgerufenen Funktion kein gültiger Visual Basic-Prozedurname ist oder mit dem Namen anderer Elemente in Ihrer Anwendung in Konflikt steht. Alias gibt den tatsächlichen Namen der aufgerufenen Funktion an.

Argument- und Datentypdeklarationen

Deklarieren Sie die Argumente und ihre Datentypen. Dieser Aspekt kann eine Herausforderung darstellen, da die von Windows verwendeten Datentypen nicht den Visual Studio-Datentypen entsprechen. Visual Basic erledigt einen Großteil dieser Aufgabe für Sie, indem Argumente in kompatible Datentypen konvertiert werden – ein Prozess, der als Marshalling bezeichnet wird. Sie können mithilfe des im System.Runtime.InteropServices-Namespace definierten MarshalAsAttribute-Attributs explizit steuern, wie Argumente gemarshallt werden.

Hinweis

In früheren Versionen von Visual Basic konnten Sie As Any-Parameter deklarieren, was bedeutet, dass Daten eines beliebigen Datentyps verwendet werden konnten. Visual Basic erfordert, dass Sie einen bestimmten Datentyp für alle Declare-Anweisungen verwenden.

Windows-API-Konstanten

Einige Argumente sind Kombinationen von Konstanten. Die in dieser exemplarischen Vorgehensweise gezeigte MessageBox-API akzeptiert beispielsweise ein ganzzahliges Argument namens Typ, das steuert, wie das Meldungsfeld angezeigt wird. Sie können den numerischen Wert dieser Konstanten ermitteln, indem Sie die #define-Anweisungen in der Datei „WinUser.h“ untersuchen. Die numerischen Werte werden im Allgemeinen im Hexadezimalformat angezeigt. Daher können Sie einen Rechner verwenden, um sie hinzuzufügen und in Dezimalwerte zu konvertieren. Wenn Sie z. B. die Konstanten für das Ausrufezeichen MB_ICONEXCLAMATION 0x00000030 und das Ja/Nein-Format MB_YESNO 0x00000004 kombinieren möchten, können Sie die Zahlen addieren und ein Ergebnis von 0x00000034 oder 52 (Dezimalwert) erhalten. Auch wenn Sie das Dezimalergebnis direkt verwenden können, ist es besser, diese Werte in Ihrer Anwendung als Konstanten zu deklarieren und dann mit dem Or-Operator zu kombinieren.

So deklarieren Sie Konstanten für Windows-API-Aufrufe
  1. Ziehen Sie die Dokumentation für die Windows-Funktion zu Rate, die Sie aufrufen. Bestimmen Sie den Namen der verwendeten Konstanten und den Namen der H-Datei, die die numerischen Werte für diese Konstanten enthält.

  2. Verwenden Sie einen Text-Editor, z. B. Editor, um den Inhalt der Headerdatei (H-Datei) anzuzeigen und die Werte zu ermitteln, die den von Ihnen verwendeten Konstanten zugeordnet sind. Beispielsweise verwendet die MessageBox-API die Konstante MB_ICONQUESTION, um ein Fragezeichen im Meldungsfeld anzuzeigen. Die Definition für MB_ICONQUESTION befindet sich in „WinUser.h“ und sieht wie folgt aus:

    #define MB_ICONQUESTION 0x00000020L

  3. Fügen Sie Ihrer Klasse oder Ihrem Modul entsprechende Const-Anweisungen hinzu, um diese Konstanten für Ihre Anwendung verfügbar zu machen. Zum Beispiel:

    Const MB_ICONQUESTION As Integer = &H20
    Const MB_YESNO As Integer = &H4
    Const IDYES As Integer = 6
    Const IDNO As Integer = 7
    
So rufen Sie die DLL-Prozedur auf
  1. Fügen Sie dem Startformular für Ihr Projekt eine Schaltfläche mit dem Namen Button1 hinzu, und doppelklicken Sie dann darauf, um den zugehörigen Code anzuzeigen. Der Ereignishandler für die Schaltfläche wird angezeigt.

  2. Fügen Sie dem Click-Ereignishandler Code für die Schaltfläche hinzu, die Sie hinzugefügt haben, um die Prozedur aufzurufen und die entsprechenden Argumente anzugeben:

    Private Sub Button1_Click(ByVal sender As System.Object,
        ByVal e As System.EventArgs) Handles Button1.Click
    
        ' Stores the return value.
        Dim RetVal As Integer
        RetVal = MBox(0, "Declare DLL Test", "Windows API MessageBox",
            MB_ICONQUESTION Or MB_YESNO)
    
        ' Check the return value.
        If RetVal = IDYES Then
            MsgBox("You chose Yes")
        Else
            MsgBox("You chose No")
        End If
    End Sub
    
  3. Führen Sie das Projekt aus, indem Sie F5 drücken. Das Meldungsfeld wird mit den Antwortschaltflächen Ja und Nein angezeigt. Klicken Sie auf eine der beiden Optionen.

Marshallen von Daten

Visual Basic konvertiert automatisch die Datentypen von Parametern und Rückgabewerten für Windows-API-Aufrufe. Sie können jedoch das MarshalAs-Attribut verwenden, um nicht verwaltete Datentypen explizit anzugeben, die von einer API erwartet werden. Weitere Informationen zum Interop-Marshalling finden Sie unter Interop-Marshalling.

So verwenden Sie Declare und MarshalAs in einem API-Aufruf
  1. Bestimmen Sie den Namen der Funktion, die Sie aufrufen möchten, sowie deren Argumente, Datentypen und den Rückgabewert.

  2. Um den Zugriff auf das MarshalAs-Attribut zu vereinfachen, fügen Sie eine Imports-Anweisung am Anfang des Codes für die Klasse oder das Modul hinzu, wie im folgenden Beispiel gezeigt:

    Imports System.Runtime.InteropServices
    
  3. Fügen Sie der verwendeten Klasse oder dem verwendeten Modul einen Funktionsprototyp für die importierte Funktion hinzu, und wenden Sie das MarshalAs-Attribut auf die Parameter oder den Rückgabewert an. Im folgenden Beispiel wird ein API-Aufruf, der den Typ void* erwartet, als AsAny gemarshallt:

    Declare Sub SetData Lib "..\LIB\UnmgdLib.dll" (
        ByVal x As Short,
        <MarshalAsAttribute(UnmanagedType.AsAny)>
            ByVal o As Object)
    

API-Aufrufe mithilfe von DllImport

Das DllImport-Attribut bietet eine zweite Möglichkeit zum Aufrufen von Funktionen in DLLs ohne Typbibliotheken. DllImport entspricht ungefähr der Verwendung einer Declare-Anweisung, bietet aber größere Kontrolle darüber, wie Funktionen aufgerufen werden.

Sie können DllImport mit den meisten Windows-API-Aufrufen verwenden, solange sich der Aufruf auf eine freigegebene (manchmal als statisch bezeichnete) Methode bezieht. Sie können keine Methoden verwenden, die eine Instanz einer Klasse erfordern. Im Gegensatz zu Declare-Anweisungen können DllImport-Aufrufe das MarshalAs-Attribut nicht verwenden.

So rufen Sie eine Windows-API mithilfe des DllImport-Attributs auf

  1. Öffnen Sie ein neues Windows-Anwendungsprojekt, indem Sie im Menü Datei auf Neu und dann auf Projekt klicken. Das Dialogfeld Neues Projekt wird angezeigt.

  2. Wählen Sie in der Liste der Visual Basic-Projektvorlagen die Option Windows-Anwendung aus. Das neue Projekt wird angezeigt.

  3. Fügen Sie dem Startformular eine Schaltfläche mit dem Namen Button2 hinzu.

  4. Doppelklicken Sie auf Button2, um die Codeansicht für das Formular zu öffnen.

  5. Um den Zugriff auf DllImport zu vereinfachen, fügen Sie am Anfang des Codes für die Startformularklasse eine Imports-Anweisung hinzu:

    Imports System.Runtime.InteropServices
    
  6. Deklarieren Sie eine leere Funktion vor der End Class-Anweisung für das Formular, und nennen Sie die Funktion MoveFile.

  7. Wenden Sie die Public- und Shared-Modifizierer auf die Funktionsdeklaration an, und legen Sie Parameter für MoveFile basierend auf den Argumenten fest, die von der Windows-API-Funktion verwendet werden:

    Public Shared Function MoveFile(
        ByVal src As String,
        ByVal dst As String) As Boolean
        ' Leave the body of the function empty.
    End Function
    

    Ihre Funktion kann einen beliebigen gültigen Prozedurnamen aufweisen. das DllImport-Attribut gibt den Namen in der DLL an. Außerdem wird das Marshalling der Interoperabilität für die Parameter und Rückgabewerte verarbeitet, sodass Sie Visual Studio-Datentypen auswählen können, die den Datentypen ähneln, die von der API verwendet werden.

  8. Wenden Sie das DllImport-Attribut auf die leere Funktion an. Der erste Parameter ist der Name und der Speicherort der DLL, die die Funktion enthält, die Sie aufrufen. Sie müssen den Pfad für Dateien in den Windows-Systemverzeichnissen nicht angeben. Der zweite Parameter ist ein benanntes Argument, das den Namen der Funktion in der Windows-API angibt. In diesem Beispiel erzwingt das DllImport-Attribut, dass Aufrufe vonMoveFile an MoveFileW in „KERNEL32.DLL“ weitergeleitet werden. Die MoveFileW-Methode kopiert eine Datei aus dem Pfad src in den Pfad dst.

    <DllImport("KERNEL32.DLL", EntryPoint:="MoveFileW", SetLastError:=True,
        CharSet:=CharSet.Unicode, ExactSpelling:=True,
        CallingConvention:=CallingConvention.StdCall)>
    Public Shared Function MoveFile(
        ByVal src As String,
        ByVal dst As String) As Boolean
        ' Leave the body of the function empty.
    End Function
    
  9. Fügen Sie dem Button2_Click-Ereignishandler Code hinzu, um die Funktion aufzurufen:

    Private Sub Button2_Click(ByVal sender As System.Object,
        ByVal e As System.EventArgs) Handles Button2.Click
    
        Dim RetVal As Boolean = MoveFile("c:\tmp\Test.txt", "c:\Test.txt")
        If RetVal = True Then
            MsgBox("The file was moved successfully.")
        Else
            MsgBox("The file could not be moved.")
        End If
    End Sub
    
  10. Erstellen Sie eine Datei mit dem Namen „Test.txt“, und platzieren Sie sie im Verzeichnis „C:\Tmp“ auf Ihrer Festplatte. Erstellen Sie bei Bedarf das Verzeichnis „Tmp“.

  11. Drücken Sie F5, um die Anwendung zu starten. Das Hauptformular wird angezeigt.

  12. Klicken Sie auf Button2. Die Meldung „The file was moved successfully“ (Die Datei wurde erfolgreich verschoben) wird angezeigt, wenn die Datei verschoben werden kann.

Weitere Informationen