Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
1 Einführung
2 Grundlagen der Sprachsyntax
3 Klassendesign
4 Weitere Datentypen
5 Multithreading
6 Collections und LINQ
7 Eingabe und Ausgabe
8 Anwendungen: Struktur und Installation
9 Code erstellen und debuggen
10 Einige Basisklassen
11 Windows-Anwendungen erstellen
12 Die wichtigsten Steuerelemente
13 Tastatur- und Mausereignisse
14 MDI-Anwendungen
15 Grafiken mit GDI+
16 Drucken
17 Entwickeln von Steuerelementen
18 Programmiertechniken
19 WPF – Grundlagen
20 Layoutcontainer
21 WPF-Steuerelemente
22 Konzepte von WPF
23 Datenbankverbindung mit ADO.NET
24 Datenbankabfragen mit ADO.NET
25 DataAdapter
26 Offline mit DataSet
27 Datenbanken aktualisieren
28 Stark typisierte DataSets
A Anhang: Einige Übersichten
Stichwort

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Visual Basic 2008 von Andreas Kuehnel, Stephan Leibbrandt
Das umfassende Handbuch
Buch: Visual Basic 2008

Visual Basic 2008
3., aktualisierte und erweiterte Auflage, geb., mit DVD
1.323 S., 49,90 Euro
Rheinwerk Computing
ISBN 978-3-8362-1171-0
Pfeil 18 Programmiertechniken
Pfeil 18.1 Drag
Pfeil 18.1.1 Ablauf der Operation
Pfeil 18.1.2 Start der Operation
Pfeil 18.1.3 Ereignisse des Empfängers
Pfeil 18.1.4 Programmbeispiele
Pfeil 18.2 API-Aufrufe mit PInvoke
Pfeil 18.2.1 Das Attribut DllImport
Pfeil 18.2.2 Datentypen von API-Funktionen
Pfeil 18.3 Windows-Dienstanwendungen entwickeln
Pfeil 18.3.1 »Windows-Dienst«-Projekte in der Entwicklungsumgebung
Pfeil 18.3.2 Methoden eines Dienstes
Pfeil 18.3.3 Eigenschaften eines Dienstes
Pfeil 18.3.4 Installation eines Windows-Dienstes
Pfeil 18.3.5 Das Beispielprogramm FileWatchService
Pfeil 18.3.6 Dienste mittels Programmcode steuern
Pfeil 18.4 Die Zwischenablage
Pfeil 18.4.1 Speichern und Abrufen von Daten
Pfeil 18.4.2 Weitere Zugriffsmethoden
Pfeil 18.4.3 Mehrere Datenformate gleichzeitig
Pfeil 18.4.4 Eigene Datenformate schreiben
Pfeil 18.4.5 Leeren der Zwischenablage
Pfeil 18.4.6 Beispielprogramm Menü »Bearbeiten«


Rheinwerk Computing - Zum Seitenanfang

18.2 API-Aufrufe mit PInvoke Zur nächsten ÜberschriftZur vorigen Überschrift

Mit seinen vielen Klassen und Methoden bietet uns das .NET Framework eine fast unbegrenzte Funktionalität. Dennoch lassen sich nicht alle Probleme damit lösen, insbesondere wenn es um spezielle Aufgaben des Betriebssystems geht. Daher steht Ihnen ein Mechanismus zur Verfügung, um externe Technologien einzusetzen. Diese Technik wird als PInvoke bezeichnet, die Abkürzung für Platform Invocation Services.

PInvoke ermöglicht den Aufruf von Funktionen unverwalteter DLL-Dateien, zu denen auch die der Win32-API gehören. Dabei steht ein Attribut im Blickpunkt, das im Namensraum System.Runtime.InteropServices definiert ist: das Attribut DllImportAttribute. Die Syntax wurde bereits in Abschnitt 3.4.3, »Externe Funktionen«, beschrieben. Hier geht es um dessen Einsatz.

Bevor wir uns damit etwas näher beschäftigen, hier ein kleines, einfaches Beispiel. In der Systemdatei user32.dll ist eine Funktion MessageBox zu finden, die genauso wie die gleichnamige Klasse im .NET Framework ein Meldungsfenster anzeigt. Wollen wir das Meldungsfenster aus der Win32-API nutzen, können wir den folgenden Code in einer Form schreiben:

Imports System.Runtime.InteropServices

Public Class Form1 : Inherits Form 
  <DllImport("user32.dll")> _ 
  Public Shared Function MessageBox(HWnd As Integer, _ 
         text As String, caption As String, type As Integer) As Integer 
  End Function

  ' alternativ: 
  ' Declare Auto Function MessageBox Lib "user32.dll" (hWnd As Integer, _ 
  '   text As String, caption As String, type As Integer ) As Integer

  Private Sub button1_Click(sender As Object, e As EventArgs) 
    MessageBox(0, "Win32-API-Meldungsfenster", "Hallo...", 0) 
  End Sub 
End Class

Das Attribut DllImport kann nur mit einer Methode verknüpft werden, wobei dem Konstruktor der Name der DLL-Datei übergeben wird, in dem sich die Funktion befindet. Befindet sich die Datei in einem Verzeichnis, das in der Systemvariablen Path eingetragen ist, brauchen Sie den Pfad zu der Datei nicht anzugeben, wie in unserem Beispiel.

Hinter dem Attribut erfolgt die Deklaration der externen Methode, die immer mit Shared an die Klasse gebunden ist. Der Grund ist recht einfach: Eine Funktion aus einer externen DLL-Datei ist niemals eine Instanzmethode, sondern steht immer global zur Verfügung.


Rheinwerk Computing - Zum Seitenanfang

18.2.1 Das Attribut DllImport Zur nächsten ÜberschriftZur vorigen Überschrift

Nicht alle Methoden einer externen Bibliothek sind so einfach aufzurufen wie die der MessageBox. Bei komplexeren Funktionen kommen unter Umständen auch benannte Parameter des Attributs ins Spiel, die der Tabelle 18.5 zu entnehmen sind.


Tabelle 18.5 Benannte Parameter von »DllImportAttribute« (E = Enumeration)

Eigenschaft Beschreibung

BestFitMapping

Gibt an, ob die Konvertierung von Unicode nach ANSI (notwendig für Windows 98 und ME) optimiert ist (Standard True).

CallingConvention

Art der Stack-Entleerung nach Aufrufen. Beim Standardwert CallingConvention.Winapi macht das das Betriebssystem.

E

CharSet

Art der verwendeten Zeichenketten (1 oder 2 Byte je Buchstabe). Standard ist Charset.Ansi.

E

EntryPoint

Name oder Nummer der externen Funktion. Muss nicht mit dem Methodennamen in Visual Basic übereinstimmen.

ExactSpelling

API-Funktionen mit angehängtem »A« unterstützen kein Unicode (z. B. Windows 98), ein »W« signalisiert Unicodeunterstützung. Beim Standardwert False wird automatisch ein Buchstabe in Abhängigkeit von CharSet angehängt.

PreserveSig

Der Standardwert True reicht einen ganzzahliger Rückgabewert HRESULT unverändert durch. Bei False löst ein HRESULT-Wert ungleich 0 in eine Ausnahme aus. Auf alle anderen Rückgabetypen hat die Eigenschaft keinen Einfluss.

SetLastError

Mit dem Nichtstandardwert True wird ein Fehler in der API-Funktion gespeichert und kann mit GetLastWin32Error der Klasse Marshal ausgelesen werden. Eine API-Funktion signalisiert einen Fehler durch die Rückgabe von False.

ThrowOnUnmappableChar

Ist BestFittingMapping=True und misslingt eine Umwandlung, wird beim Nichtstandardwert True eine Ausnahme ausgelöst.


Exemplarisch zeigt das folgende Codefragment den Import der API-Funktion MessageBox unter dem Alias Meldungsfenster. Der Wert des Attributs EntryPoint spezifiziert den Originalnamen der Funktion innerhalb der DLL.

<DllImport("user32.dll", EntryPoint="MessageBox")> _ 
Public Shared Function Meldungsfenster(HWnd As Integer, _ 
       text As String, caption As String, type As Integer) As Integer 
End Function

Private Sub button1_Click(sender As Object, e As EventArgs) 
  Meldungsfenster(0, "Win32-API-Meldungsfenster", "Hallo...", 0) 
End Sub

Rheinwerk Computing - Zum Seitenanfang

18.2.2 Datentypen von API-Funktionen topZur vorigen Überschrift

Bei nahezu jedem Aufruf einer API-Funktion müssen Sie Datentypen angeben. So einfach sich das im ersten Moment anhört, so schwierig ist dabei oft die Umsetzung. Da die meisten Funktionen in den APIs in C/C++ geschrieben sind, finden viele Datentypen keine direkte Entsprechung in Visual Basic (oder, um es allgemeiner auszudrücken, im .NET Framework). Geben Sie aber einen falschen Typ an, kommt es zu einem Laufzeitfehler.

Das Umsetzen eines VB-Datentyps in einen API-Datentyp wird als Marshalling bezeichnet. Im .NET Framework kann mit dem Attribut MarshalAs das Umsetzen gesteuert werden. Das Attribut wird bei dem Parameter angegeben, der einer API-Funktion übergeben wird. Wahrscheinlich am häufigsten kommt ein positionaler Parameter zum Einsatz, der in der Enumeration UnmanagedType definiert ist. Funktionen, die beispielsweise einen der C++-Datentypen LPStr (nullterminierter ASCII-String) oder LPWStr (nullterminierter Unicode-String) erwarten, kann mit MarshalAs ein VB-String übergeben werden.

Im folgenden Beispiel wird mit der Funktion GetDiskFreeSpaceEx aus der Bibliothek kernel32.dll das frei verfügbare und gesamte Speichervolumen eines Laufwerks ermittelt. Die Originaldefinition lautet:

BOOL GetDiskFreeSpaceEx { 
  LPCTSTR lpDirectoryName, 
  PULARGE_INTEGER lpFreeBytesAvailable, 
  PULARGE_INTEGER lpTotalNumberOfBytes, 
  PULARGE_INTEGER lpTotalNumberOfFreeBytes 
};

Dem ersten Parameter wird eine Zeichenfolge übergeben, die das zu untersuchende Laufwerk angibt. In allen anderen Parametern werden von der Funktion die Ergebnisse an den Aufrufer übermittelt. Im zweiten Parameter handelt es sich um die nutzbaren Bytes, die vom aufrufenden Thread genutzt werden können, im dritten die Größe des angegebenen Laufwerks und im vierten um das Gesamtvolumen der unbelegten Bytes.

Damit die Übergabe des Laufwerks als String korrekt gemarshallt werden kann, wird dem ersten Argument das MarshalAs-Attribut vorangestellt; alle anderen Argumente sind vom ganzzahligen Typ Long.

Der Rückgabewert der API-Funktion ist vom Typ BOOL, der 4 Byte groß ist und eine von 0 abweichende Zahl liefert, wenn der Aufruf erfolgreich war. Entgegengenommen wird der Rückgabewert in einem Integer, er lässt sich aber auch direkt in einer Bedingung auswerten.


'...\Programmiertechniken\PInvoke\Plattenplatz.vb

Imports System.Runtime.InteropServices 
Namespace PInvoke 
  Module Plattenplatz 
    <DllImport("Kernel32.dll")> _ 
    Private Function GetDiskFreeSpaceEx( _ 
      <MarshalAs(UnmanagedType.LPStr)> ByVal lpDirectoryName As String, _ 
      ByRef lpFreeBytesAvailable As Long, _ 
      ByRef lpTotalNumberOfBytes As Long, _ 
      ByRef lpTotalNumberOfFreeBytes As Long) As Integer 
    End Function

    Sub Druck() 
      Dim disk As String = "C:\" 
      Dim verfügbar, total, frei 
      If 0 <> GetDiskFreeSpaceEx(disk, verfügbar, total, frei) Then 
        Console.WriteLine("Freie Bytes (User)      = {0}", verfügbar) 
        Console.WriteLine("Verfügbare Bytes (User) = {0}", total) 
        Console.WriteLine("Freie Bytes (total)     = {0}", frei) 
      End If 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace

Das Umsetzen der Datentypen ist ein sehr großer Themenkreis, auf den wir hier nicht tiefer eingehen wollen. Für weitergehende Informationen sei auf die Online-Dokumentation verwiesen.

Zum Abschluss dieses Abschnitts soll noch ein weiteres Beispiel einer API-Funktion gezeigt werden, mit der es möglich ist, eine Wave-Datei in einer .NET-Anwendung abzuspielen. Hierbei handelt es sich um die Funktion sndPlaySound der Bibliothek winmm.dll.

BOOL sndPlaySound { 
  LPCSTR lpszSound, 
  UINT fuSound 
};

Der erste Parameter erwartet die Angabe einer Wave-Datei, dem zweiten werden Konstanten übergeben, mit denen das Verhalten der Funktion gesteuert wird. Die Auswertung des zweiten Parameters erfolgt bitweise. Mit SND_ASYNC lässt sich dabei festlegen, dass der Sound asynchron abgespielt wird, SND_LOOP sagt aus, dass der Sound so lange gespielt wird, bis die Funktion erneut aufgerufen wird. Sollte die angegebene Wave-Datei nicht gefunden werden, wird per Voreinstellung der Standardsound abgespielt. Mit der Konstanten SND_NODEFAULT lässt sich das abstellen.

Eine Hürde im Zusammenhang mit API-Funktionen ist es häufig, die Werte der Konstanten zu ermitteln, da diese in den Dokumentationen nicht mit angegeben werden. Oftmals genügt ein Blick in die C/C++-Headerdateien, um einen Wert in Erfahrung zu bringen. Ganzzahlige Konstanten versuche ich immer in einer Enumeration unterzubringen, um nur definierte Werte zu erlauben.


'...\Programmiertechniken\PInvoke\Plattenplatz.vb

Imports System.Runtime.InteropServices 
Namespace PInvoke 
  Module Wave 
    <DllImport("winmm.dll")> _ 
    Private Function sndPlaySound(ByVal lpszSound As String, _ 
                                  ByVal fuSound As Integer) As Integer 
    End Function

    <Flags()> Private Enum Sound 
      SND_ASYNC = &H1     ' asynchron abspielen 
      SND_NODEFAULT = &H2 ' Standardsound bei Problemen 
      SND_LOOP = &H8      ' Wiederholung bis zum erneuten Aufruf 
    End Enum

    Sub Ausgabe() 
      Dim flags As Integer = 0 
      Console.Write("Asynchrones Abspielen? (j/n)") 
      If "j" = Console.ReadLine() Then flags = flags Or Sound.SND_ASYNC 
      Console.Write("Wiederholtes Abspielen? (j/n)") 
      If "j" = Console.ReadLine() Then flags = flags Or Sound.SND_LOOP 
      Console.Write("Standardsound abspielen? (j/n)") 
      If "n" = Console.ReadLine() Then flags = flags Or Sound.SND_NODEFAULT 
      ' Datei abspielen 
      sndPlaySound("ringin.wav", flags) 
      Console.ReadLine() 
    End Sub 
  End Module 
End Namespace


Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Visual Basic 2008
Visual Basic 2008
Jetzt Buch bestellen


 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Rheinwerk-Shop: Visual Basic 2012






 Visual Basic 2012


Zum Rheinwerk-Shop: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Rheinwerk-Shop: IT-Handbuch für Fachinformatiker






 IT-Handbuch für
 Fachinformatiker


Zum Rheinwerk-Shop: Professionell entwickeln mit Visual C# 2012






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Rheinwerk-Shop: Windows Presentation Foundation






 Windows Presentation
 Foundation


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2009
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern