Windows Scripting
Netzwerke, Betriebssysteme, Sicherheit ... hierzu bietet Ihnen die Reihe net.com umfassende, praxisnahe Information. Neben Fragen der Systemverwaltung greift sie auch Themen wie Protokolle, Technologien und Tools auf. Profitieren Sie bei Ihrer täglichen Arbeit vom Praxiswissen unserer erfahrenen Autoren.
Windows Server 2003 R2 Eric Tierling 1416 Seiten, € 49,95 [D] ISBN 978-3-8273-2463-4 Der Bestseller zu Windows Server 2003 jetzt aktuell zur Version R2. Die detaillierte Beschreibung von Active Directory, Gruppenrichtlinien, Windows NT-Domänenupgrade, TCP/IP-Diensten und Sicherheitsmerkmalen ermöglicht Unternehmen einen optimalen Einsatz. Clustering, E-Mail-Server, GPMC, Terminaldienste, Remotedesktop und Webverwaltung, Volumen-Schattenkopie sowie die Smartcard-Integration und sichere WirelessLAN-Unterstützung stellen weitere Highlights dieses Buches dar. Ebenfalls berücksichtigt werden WSUS sowie 64-Bit-Computing. Mit einer 180-Tage Trial-Version von Windows Server 2003 R2 auf zwei CDs.
Planungsbuch Microsoft-Netzwerke Thomas Joos 848 Seiten, € 59,95 [D] ISBN 978-3-8273-2386-6 IT-Leiter, -Administratoren und -Berater erhalten mit diesem Buch kompetente Informationen zur Planung eines Netzwerks mit Microsoft-Technologien (Windows Server 2003 R2, Exchange Server 2003 SP2, ISA 2004 SP2, WSUS, SharePoint u.v.m.). Themen sind u.a. Viren-und Spamschutz, Notfallkonzepte, VPN und Terminalserver. Sie finden einen Vergleich der verschiedenen Serverversionen und Speichermedien und erfahren alles über das perfekte Zusammenspiel der wichtigsten Produkte.
Holger Schwichtenberg
Windows Scripting Automatisierte Systemadministration mit dem Windows Script Host und der Windows PowerShell Band 1
An imprint of Pearson Education München • Boston • San Francisco • Harlow, England Don Mills, Ontario • Sydney • Mexico City Madrid • Amsterdam
Bibliografische Information Der Deutschen Bibliothek Die Deutsche Bibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.ddb.de abrufbar.
Die Informationen in diesem Produkt werden ohne Rücksicht auf einen eventuellen Patentschutz veröffentlicht. Warennamen werden ohne Gewährleistung der freien Verwendbarkeit benutzt. Bei der Zusammenstellung von Texten und Abbildungen wurde mit größter Sorgfalt vorgegangen. Trotzdem können Fehler nicht vollständig ausgeschlossen werden. Verlag, Herausgeber und Autoren können für fehlerhafte Angaben und deren Folgen weder eine juristische Verantwortung noch irgendeine Haftung übernehmen. Für Verbesserungsvorschläge und Hinweise auf Fehler sind Verlag und Herausgeber dankbar. Alle Rechte vorbehalten, auch die der fotomechanischen Wiedergabe und der Speicherung in elektronischen Medien. Die gewerbliche Nutzung der in diesem Produkt gezeigten Modelle und Arbeiten ist nicht zulässig. Fast alle Hard- und Softwarebezeichnungen und weitere Stichworte und sonstige Angaben, die in diesem Buch verwendet werden, sind als eingetragene Marken geschützt. Da es nicht möglich ist, in allen Fällen zeitnah zu ermitteln, ob ein Markenschutz besteht, wird das ® Symbol in diesem Buch nicht verwendet. Umwelthinweis: Dieses Buch wurde auf chlorfrei gebleichtem Papier gedruckt.
10 9 8 7 6 5 4 3 2 1 09 08 07 ISBN 978-3-8273-2423-8
© 2007 by Addison-Wesley Verlag, ein Imprint der Pearson Education Deutschland GmbH, Martin-Kollar-Straße 10–12, D-81829 München/Germany Alle Rechte vorbehalten Einbandgestaltung: Marco Lindenbeck, webwo GmbH,
[email protected] Lektorat: Sylvia Hasselbach,
[email protected] Korrektorat: Petra Kienle,
[email protected] Herstellung: Claudia Bäurle,
[email protected] Satz: mediaService, Siegen, www.media-service.tv Druck und Verarbeitung: Bercker, Kevelaer Printed in Germany
Überblick
Band 1 Teil A Einführung
1
1
Über den Autor Dr. Holger Schwichtenberg
3
2
Vorwort
5
3
Leser-Portal (Dienstleistungen für Leser nach dem Kauf)
15
4
Fragen und Antworten zu diesem Buch (FAQ)
17
5
Einführung
45
6
Scripting-Schnellstart
61
Teil B Active Scripting
67
7
Das Component Object Model (COM)
69
8
Die Visual Basic-Sprachfamilie
151
9
Die Scripting Hosts
233
10 Basisfunktionen
411
11 Verzeichnisdienste
467
12 Universal-Scripting-Komponenten
615
13 Benutzerschnittstelle
739
Stichwortverzeichnis
759
V
Überblick
Band 2 14 Daten und Dokumente
791
15 Netzwerk und Kommunikation
875
16 Sicherheitskomponenten
989
17 Sonstige Scripting-Komponenten
995
18 Werkzeuge
1013
19 Fortgeschrittene Active Scripting-Techniken
1073
20 Fallbeispiele
1173
Teil C PowerShell
1219
21 .NET Framework
1221
22 Einführung in die Windows PowerShell (PS)
1229
23 PowerShell-Werkzeuge
1291
24 Systemautomatisierung mit der PowerShell
1297
25 Verzeichnisdienst-Scripting mit der PowerShell
1321
Teil D Anhang
1347
26 Grundlagen objektorientierter Komponentenarchitekturen
1349
27 Kurzeinführung in XML
1369
28 Visual Basic-Funktionen
1387
29 Literaturverzeichnis
1399
30 Abkürzungsverzeichnis
1413
Stichwortverzeichnis
VI
1423
Inhaltsverzeichnis
Band 1 Teil A Einführung
1
1
Über den Autor Dr. Holger Schwichtenberg
3
2
Vorwort
5
2.1 2.2 2.3 2.4 2.5 2.6
Vorwort zur 5. Auflage Auszug aus dem Vorwort zur 4. Auflage (2004) Auszug aus dem Vorwort zur 3. Auflage (2002) Auszug aus dem Vorwort zur 2. Auflage (2001) Auszug aus dem Vorwort zur 1. Auflage (2000) Auszug aus dem Feedback zu den bisherigen Auflagen
5 6 7 9 10 11
3
Leser-Portal (Dienstleistungen für Leser nach dem Kauf)
15
4
Fragen und Antworten zu diesem Buch (FAQ)
17
4.1
17 17 17 18 18 18 18 19
4.2
Fragen zum Inhalt des Buchs 4.1.1 Wer ist die Zielgruppe dieses Buchs? 4.1.2 Welche Kenntnisse werden in diesem Buch vorausgesetzt? 4.1.3 Woher kann ich diese Grundlagenkenntnisse bekommen? 4.1.4 Für wen ist dieses Buch nicht geeignet? 4.1.5 Was ist der Schwerpunkt dieses Buchs? 4.1.6 Was bedeutet der Titel der Buchreihe „net.com“? 4.1.7 Wie positioniert sich dieses Buch zu Ihren anderen Büchern? 4.1.8 Finde ich in diesem Buch Informationen, die es nicht in der MSDN-Bibliothek gibt? 4.1.9 Woher beziehen Sie Informationen, die Sie in diesem Buch niederschreiben? 4.1.10 Warum lassen Sie manche Details aus? 4.1.11 Wie treffen Sie die Entscheidung, welche Themen in das Buch kommen und welche nicht? 4.1.12 Sind Teile des Buchs aus anderen Büchern übernommen? 4.1.13 Wie sollte ich dieses Buch lesen? Fragen zu den sprachlichen Konventionen 4.2.1 Wie halten Sie es mit Anglizismen? 4.2.2 Wie grenzen Sie die Windows-Versionen sprachlich ab? 4.2.3 Wie grenzen Sie die verschiedenen Visual Basic-Dialekte und Versionen voneinander ab?
20 20 21 21 21 21 22 22 22 22
VII
Inhaltsverzeichnis
4.2.4
4.3
4.4
4.5
4.6
4.7
VIII
Wie grenzen Sie die Begriffe Automation und Automatisierung ab? 4.2.5 Was bedeutet MINFU? Fragen zur Gestaltung des Buchs 4.3.1 Wie werden die Informationen in diesem Buch dargestellt? 4.3.2 Welche Formatierungen kommen in diesem Buch zum Einsatz? 4.3.3 Sind die Bildschirmabbildungen in diesem Buch in Deutsch oder Englisch? 4.3.4 Welche grafische Notation verwenden Sie in den Objektdiagrammen? 4.3.5 Wie vollständig sind die Objektdiagramme? 4.3.6 Was bedeutet es, wenn hinter einem Wort ein leeres Klammernpaar steht? 4.3.7 Wieso verweisen Sie bei Querverweisen nur auf Themen, nicht aber direkt auf die Kapitelnummer? Fragen zur Buch-CD-ROM 4.4.1 Was befindet sich auf der CD-ROM? 4.4.2 Wie finde ich die Codebeispiele auf der Begleit-CD-ROM wieder? 4.4.3 Was kann ich tun, wenn die CD-ROM zu meinem Buch fehlt oder defekt ist? Fragen zu den Programmcodebeispielen 4.5.1 Warum gibt es in diesem Buch nur Beispielcode in Visual Basic Script und nicht auch in JavaScript (JScript)? 4.5.2 Nach welchen Richtlinien erstellen Sie Codebeispiele? 4.5.3 Was bedeutet die Methode say(), die in einigen Listings steht? 4.5.4 Was bedeuten die unterschiedlichen Kommentararten? 4.5.5 Was bedeutet die Kommentare, in denen „as“ vorkommt? 4.5.6 Welche Infrastruktur haben Sie für dieses Buch verwendet? 4.5.7 Wie kann ich feststellen, welche Scripting-Komponenten auf meinem System installiert sind? 4.5.8 Woher bekomme ich die notwendigen Scripting-Komponenten? 4.5.9 Was muss ich tun, wenn die Fehlermeldung „Projekt oder Bibliothek nicht gefunden“ erscheint? Fragen zur Qualitätssicherung 4.6.1 Gibt es eine Qualitätssicherung für die Inhalte in diesem Buch? 4.6.2 Wie kann es sein, dass trotz der Qualitätssicherungsmaßnahmen Programmbeispiele aus Ihrem Buch auf meinem Rechner nicht funktionieren? Fragen zur Unterstützung nach dem Kauf 4.7.1 Gibt es Unterstützung nach dem Kauf eines Buchs? 4.7.2 Antworten Sie auf E-Mails, in denen ein Leser eine inhaltliche Frage stellt? 4.7.3 Wenn ich einen Fehler in dem Buch finde, möchten Sie dann, dass ich Sie darauf hinweise? 4.7.4 Bieten Sie auch kommerzielle Unterstützung für Scripting, .NET und PowerShell?
23 23 23 23 23 24 24 29 29 29 30 30 31 33 33 33 33 34 34 35 35 37 38 40 41 41
41 42 42 42 43 43
Inhaltsverzeichnis
5
Einführung
45
5.1 5.2 5.3 5.4 5.5
45 46 47 48 49 51 52 53 55 55 56 56 58 58 59
5.6 5.7 5.8
6
Der Automatisierungsbedarf Was ist Scripting? Automatisierungslösungen auf der Windows-Plattform Die DOS-Batchsprache Die Active Scripting-Architektur 5.5.1 Active Scripting Hosts 5.5.2 Active Scripting Engines 5.5.3 COM-Komponenten 5.5.4 Werkzeugunterstützung 5.5.5 Active Scripting versus VBA Scripting im .NET Framework Die Microsoft Powershell Neuerungen in Windows Vista im Überblick 5.8.1 Scriptumgebungen 5.8.2 Scriptbibliotheken
Scripting-Schnellstart
61
6.1 6.2 6.3 6.4
61 62 63 64
Ein einfaches Script für den Windows Script Host Ein komplexeres Script mit zwei Sprachen für den Internet Explorer Benutzer aus dem Active Directory exportieren Ein PowerShell-Beispiel
Teil B Active Scripting
67
7
Das Component Object Model (COM)
69
7.1 7.2 7.3 7.4
69 70 70 72 73 75 76 77 77 78 78 79 81 83
7.5 7.6
7.7 7.8
Binärstandard Programmiersprachen für COM COM-Laufzeitumgebungen COM-Bausteine 7.4.1 Die wichtigsten Bausteine im Kurzüberblick 7.4.2 Global Unique Identifier (GUIDs) 7.4.3 Moniker COM-Dienste COM-Konfigurationsdaten 7.6.1 Die Registrierungsdatenbank als Konfigurationsspeicher 7.6.2 XML-Konfigurationsdateien Komponentenarten Verpackungsformen 7.8.1 EXE-Server im Vergleich zu DLL-Server 7.8.2 Der Zusammenhang zwischen Komponentenart und Verpackungsform 7.8.3 Zusatzinformationen
83 84
IX
Inhaltsverzeichnis
7.9 Registrierung von Komponenten 7.10 COM-Klassen 7.10.1 Klassenidentifikation mit CLSIDs 7.10.2 Programmatic Identifier 7.10.3 Friendly Class Name 7.10.4 Klassen in der Registrierungsdatenbank 7.11 COM-Schnittstellen 7.11.1 Standardschnittstelle einer COM-Klasse 7.11.2 Namensgebung 7.11.3 Schnittstellen in der Registrierungsdatenbank 7.11.4 Virtuelle Tabellen 7.11.5 Die Grauzone zwischen Klasse und Schnittstelle 7.11.6 Mangelnde Selbsterkenntnis bei den Schnittstellen 7.11.7 Bullet-and-Stick-Diagramme 7.12 Klassenmitglieder 7.13 Typinformationen 7.13.1 Interface Definition Language (IDL) 7.13.2 Typbibliotheken 7.14 Statischer Aufruf versus Automation 7.15 COM-Standardschnittstellen 7.15.1 Statisches Binden mit IUnknown 7.15.2 Automation mit IDispatch 7.15.3 Duale Schnittstellen 7.15.4 DispatchEx 7.16 Distributed COM (DCOM) 7.16.1 DCOM-Protokoll 7.16.2 DCOM-Installation und -Konfiguration 7.16.3 DCOM im Internet 7.17 Objektaktivierung 7.17.1 Service Control Manager (SCM) 7.17.2 Erzeugung neuer Instanzen 7.17.3 Zugriff auf bestehende Instanzen 7.17.4 Aktivierungsfehler 7.18 COM-Anwendungen 7.19 COM-Assemblies 7.20 COM-Kategorien 7.21 Persistenz und Structured Storage 7.22 COM-Sicherheit 7.22.1 Authentifizierung 7.22.2 Identität 7.22.3 Impersonifizierung 7.22.4 Zugriffsberechtigungen 7.23 Active Scripting 7.23.1 Entwicklung von Scripting Engines 7.23.2 Installierte Scripting Engines
X
85 85 86 86 87 87 89 89 90 90 90 91 92 93 94 95 97 99 101 103 104 105 107 108 108 109 109 110 112 112 113 115 117 118 119 123 124 126 127 127 128 129 131 131 132
Inhaltsverzeichnis
7.24
7.25
7.26
7.27
7.28 8
7.23.3 Entwicklung von Scripting Hosts 7.23.4 COM-Komponenten beim Active Scripting 7.23.5 Eingebaute Objekte Microsoft Transaction Server (MTS) 7.24.1 MTS-Administration 7.24.2 Interception 7.24.3 Packages 7.24.4 Programmierung COM+ 7.25.1 Änderungen gegenüber dem MTS 7.25.2 Neue Dienste in COM+ 7.25.3 COM+-Administration Objektmodelle in COM-Komponenten 7.26.1 Objektorientierte Konzepte in COM 7.26.2 Bausteine von COM-Objektmodellen 7.26.3 Empfehlungen für Objektmodelle 7.26.4 Metaobjektmodelle Bewertung von COM 7.27.1 Vorteile von COM 7.27.2 COM auf anderen Plattformen 7.27.3 Unzulänglichkeiten von COM .NET Framework („DOTNET“)
133 133 133 134 134 135 135 136 136 137 138 138 139 139 140 141 142 146 147 147 147 150
Die Visual Basic-Sprachfamilie
151
8.1
153 154 154 156 156 156 156 156 158 158 158 159 160 161 161 162 163 163 164 166
8.2
8.3
8.4
8.5
Die Visual Basic-Sprachfamilie 8.1.1 Visual Basic for Applications (VBA) 8.1.2 Visual Basic Script (VBS) 8.1.3 Embedded Visual Basic (eVB) 8.1.4 Visual Basic .NET 8.1.5 Anwendungsgebiete Grundlagen 8.2.1 Grundlegendes zur Syntax 8.2.2 Speicherung des Programmcodes 8.2.3 Startpunkt eines Programms Einfache Ein- und Ausgabefunktionen 8.3.1 Ausgaben mit MsgBox() 8.3.2 Eingaben mit InputBox() empfangen Variablen 8.4.1 Gültigkeitsbereich von Variablen 8.4.2 Benennung von Variablen Datentypen 8.5.1 Datentypen in VBS 8.5.2 Datentypen in VB 6.0/VBA 8.5.3 Startwerte von Variablen
XI
Inhaltsverzeichnis
8.6
8.7 8.8 8.9
8.10
8.11
8.12
8.13 8.14
8.15
8.16 8.17 8.18
XII
Darstellung von Werten 8.6.1 Literale 8.6.2 Symbolische Konstanten Operatoren Typkonvertierung Datenfelder (Arrays) 8.9.1 Statische Arrays 8.9.2 Dynamische Arrays 8.9.3 Array-Operationen Bedingungen 8.10.1 If...Then 8.10.2 Select...Case Schleifen 8.11.1 For...Next 8.11.2 For Each...Next 8.11.3 Do...Loop Unterroutinen 8.12.1 Prozeduren 8.12.2 Funktionen 8.12.3 Die Last mit den Parametern Codegenerierung zur Laufzeit Objektbasierte Programmierung 8.14.1 Definition von Klassen in VBS 8.14.2 Definition von Klassen in VB 6.0/VBA 8.14.3 Objektvariablen 8.14.4 Instanziierung 8.14.5 Objektverwendung 8.14.6 Objektoperationen 8.14.7 Property-Routinen 8.14.8 Objektvernichtung 8.14.9 Objektmengen (Collections) 8.14.10 Ereignisse 8.14.11 Vererbung und Mehrfachschnittstellen Nutzung von COM und DCOM 8.15.1 Instanziierung von COM-Komponenten 8.15.2 Zugriff auf bestehende Instanzen 8.15.3 Verwendung von COM-Objekten 8.15.4 Verwendung von Mehrfachschnittstellen 8.15.5 Datentypprobleme beim Zugriff auf COM-Komponenten Eingebaute Funktionen und Klassen Fehlerbehandlung Allgemeine Hilfsroutinen 8.18.1 Scripteinbindung 8.18.2 Umwandlungsroutinen 8.18.3 Rückumwandlung von Konstanten
166 167 168 171 173 175 175 176 176 181 181 182 184 184 186 187 190 190 191 192 194 196 196 198 199 199 200 202 203 208 208 211 213 216 217 219 220 220 221 222 222 225 225 226 226
Inhaltsverzeichnis
8.18.4 8.18.5 8.18.6 8.18.7 9
Ausgabe Schreiben in eine Log-Datei Fehlerüberprüfung COM-Funktionen
227 228 229 229
Die Scripting Hosts
233
9.1
236 236 238 238 241 245 253 254 258 259 260 271 271 279 283 283 284 285 286 291 293 296 298 299 300 300 309 309 311 311 312 314 314 330 334 336 337 338 339
9.2
9.3 9.4
Windows Script Host (WSH) 9.1.1 Verfügbare Versionen 9.1.2 WSH-Installation 9.1.3 WSH-Konfiguration 9.1.4 WScript versus CScript 9.1.5 Scriptdateien 9.1.6 Start eines Script 9.1.7 Befehlszeilenparameter für Scripts 9.1.8 Einbinden von anderen Scriptdateien 9.1.9 Statische Objekte und Einbinden von Typbibliotheken 9.1.10 Die eingebauten Objekte des WSH 9.1.11 Bildschirmmasken für den WSH 9.1.12 Sicherheitseinstellungen 9.1.13 Sicherheit in Windows Vista DHTML-Scripting im Internet Explorer 9.2.1 Grundlagen des Browser-Scripting 9.2.2 Einbindung von Scriptcode 9.2.3 Hello World im Browser 9.2.4 Sicherheitseinstellungen 9.2.5 DOM-Ereignisbehandlung 9.2.6 Eingebaute Objekte (Intrinsic Objects) 9.2.7 Zugriff auf externe COM-Komponenten 9.2.8 HTML-Applications (HTAs) Microsoft Gadgets Active Server Pages (ASP) 9.4.1 Grundlagen dynamischer Webserveranwendungen 9.4.2 Installation von ASP 9.4.3 IIS-Konfiguration 9.4.4 Aufbau von ASP-Seiten 9.4.5 Start einer ASP-Seite 9.4.6 Ausgaben in ASP 9.4.7 Render-Funktionen 9.4.8 Eingebaute Objekte 9.4.9 Global.asa und ASP-Ereignisse 9.4.10 Einbinden von Dateien 9.4.11 Einbinden von Typbibliotheken 9.4.12 Fehlermeldungen 9.4.13 Sicherheitseinstellungen 9.4.14 Transaktionssteuerung
XIII
Inhaltsverzeichnis
9.5
9.6
9.7 9.8
9.9
9.10
9.11 9.12 9.13
Job Scripting im Microsoft SQL Server 7.0/2000/2005 9.5.1 Überblick über den SQL Server-Agent 9.5.2 Definition von Aufträgen 9.5.3 Erstellung von Job Scripts 9.5.4 Eingebaute Objekte (Intrinsic Objects) Data Transformation Service (DTS) im Microsoft SQL Server 7.0/2000 9.6.1 DTS-Pakete 9.6.2 Datentransformationen mit dem DTS 9.6.3 ActiveX Script-Transformation 9.6.4 ActiveX ScriptTasks Microsoft SQL Server 2005 Integration Services (SSIS) Scripting im Microsoft Operations Manager (MOM) 2000/2005 9.8.1 Bausteine 9.8.2 Management Packs 9.8.3 Architektur 9.8.4 Überblick über das Regelsystem 9.8.5 Computergruppierungsregeln 9.8.6 Verarbeitungsregeln 9.8.7 Antworten auf die Erfüllung von Regeln 9.8.8 Scripting im MOM Event Scripting Agent im Exchange Server 5.5/2000/2003 9.9.1 Überblick über den Exchange Event Service 9.9.2 Exchange Event Scripting Microsoft Outlook Forms 9.10.1 Formulardesigner 9.10.2 Steuerelemente und Felder 9.10.3 Eingebaute Objekte (Intrinsic Objects) 9.10.4 Ereignisse in Outlook Forms Windows Installer Custom Actions XSLT-Scripting Scripting Hosts anderer Anbieter 9.13.1 System Script Host (SSH) 9.13.2 OnScript Host (OSH) 9.13.3 HyperHost 9.13.4 TextPipe
10 Basisfunktionen 10.1 WSH-Laufzeitbibliothek (WSH Runtime Library) 10.1.1 Objektmodelle der WSH Runtime Library 10.1.2 WSHNetwork und untergeordnete Klassen 10.1.3 WSHShell und untergeordnete Klassen 10.2 Scripting-Laufzeitumgebung (Scripting Runtime Library) 10.2.1 Daten speichern in der Dictionary-Klasse 10.2.2 File System Objects (FSO) 10.2.3 Zugriff auf die Dateisystemstruktur 10.2.4 Zugriff auf Dateiinhalte (Textstreams)
XIV
339 340 341 344 346 347 348 353 358 359 362 363 364 364 365 366 367 370 376 378 389 390 392 402 402 403 404 405 406 406 407 408 409 410 410 411 412 413 420 423 439 440 443 445 460
Inhaltsverzeichnis
11 Verzeichnisdienste 11.1 Active Directory Service Interface (ADSI) 11.1.1 Verzeichnisdienste 11.1.2 Die ADSI-Grundlagen 11.1.3 Das ADSI-Meta-Objektmodell 11.1.4 Grundlagen der ADSI-Programmierung 11.1.5 ADS Namespaces Container 11.2 ADSI-Provider „WinNT“ für SAM-basierte Benutzerdatenbanken 11.2.1 WinNT-Objektmodell 11.2.2 Identifikation und Bindung 11.2.3 Verwaltung von NT-Domänen 11.2.4 Die WinNT-Klasse „Computer“ 11.2.5 Benutzerkonten verwalten mit der „User“-Klasse 11.2.6 Gruppenverwaltung 11.2.7 Verwaltung von Windows-Diensten 11.2.8 Verzeichnisfreigaben verwalten 11.2.9 Benutzersitzungen und geöffnete Ressourcen 11.2.10 Druckersteuerung 11.3 Active Directory-Administration mit ADSI 11.3.1 Allgemeine Informationen zum Active Directory 11.3.2 Active Directory Application Mode (ADAM) 11.3.3 Programmierschnittstellen 11.3.4 Das Objektmodell des Active Directory 11.3.5 Identifikation und Bindung 11.3.6 Verzeichnisattribute 11.3.7 Suchanfragen im Active Directory 11.3.8 Besondere ADS-Datentypen 11.3.9 Vergleich zum WinNT-Provider 11.3.10 Benutzerverwaltung im Active Directory 11.3.11 Benutzerauthentifizierung 11.3.12 Benutzer suchen 11.3.13 Gruppenverwaltung im Active Directory 11.3.14 Verwaltung der Organisationseinheiten im Active Directory 11.3.15 Computerverwaltung im Active Directory 11.3.16 Gruppenrichtlinienverwaltung 11.3.17 Schemazugriff 11.4 Administration eines Exchange Server 5.5 mit ADSI 11.5 Administration des Internet Information Server mit ADSI 11.5.1 IIS-Objektmodell 11.5.2 Identifikation und Bindung 11.5.3 Arbeit mit virtuellen Webservern 11.5.4 Sicherung der IIS-Metabase 11.6 System-Info-Klassen für ADSI 11.6.1 WinNTSystem 11.6.2 ADSystemInfo
467 470 471 476 480 487 504 506 507 508 509 511 511 516 517 519 520 521 521 522 525 525 526 528 531 532 535 537 538 550 551 552 557 559 561 561 562 562 563 565 565 569 570 570 570
XV
Inhaltsverzeichnis
11.7 Zusatzkomponenten für ADSI 11.7.1 ADSI-Versionsabfrage mit ADsVersion 11.7.2 Detaillierte Fehlermeldungen mit ADsError 11.7.3 GetObject() durch die Hintertür mit ADsFactory 11.7.4 RAS-Konfiguration mit ADsRAS 11.7.5 Zugriff auf Sicherheitseinstellungen mit ADsSecurity 11.7.6 Beispiel 11.7.7 IADsTools 11.8 Group Policy Objects (GPO) 11.8.1 Grundlagen zur Gruppenrichtlinienverwaltungskonsole 11.8.2 GPO-Objektmodell 11.8.3 Hilfsroutinen 11.8.4 Informationen ausgeben 11.8.5 Verknüpfungen verwalten 11.8.6 Weitere Möglichkeiten 12 Universal-Scripting-Komponenten 12.1 Windows Management Instrumentation (WMI) 12.1.1 WMI-Grundlagen 12.1.2 Metaobjektmodell in der WMI-COM-Komponente 12.1.3 Arbeit mit der WMI-Komponente 12.1.4 Abfragen mit WQL 12.1.5 WMI ODBC-Treiber 12.2 WMI im Einsatz 12.2.1 Computerverwaltung 12.2.2 Dateisystemverwaltung 12.2.3 Registrierungsdatenbank (Registry) 12.2.4 Hardware 12.2.5 Softwareverwaltung 12.2.6 Prozesse 12.2.7 Zeitplandienst 12.2.8 Benutzer und Gruppen 12.2.9 Druckerverwaltung 12.2.10 Systemdienste 12.2.11 Netzwerkkonfiguration 12.2.12 Leistungsdaten 12.2.13 Terminaldienste 12.2.14 Ereignisprotokolle 12.2.15 Exchange Server-Administration mit WMI 12.2.16 IIS-Administration mit WMI 12.2.17 Beispiel 12.2.18 Informationen über WMI selbst 12.2.19 Ihre Expedition in die WMI
XVI
571 571 572 573 574 577 589 590 590 591 595 597 599 603 613 615 615 616 639 648 663 670 671 671 678 685 689 690 694 697 699 701 703 707 715 715 716 719 727 727 728 730
Inhaltsverzeichnis
12.3 Windows Remote Management (WinRM) 12.3.1 Nutzung von WinRM 12.3.2 Objektmodell der WinRM Scripting Objects 12.3.3 Adressierung 12.3.4 WinRM im Einsatz 13 Benutzerschnittstelle
730 732 732 733 733 739
13.1 Microsoft Shell Objects 13.1.1 Objektmodell der Shell Objects 13.1.2 Arbeit mit Explorer-Fenstern 13.1.3 Arbeiten mit Ordnern und Dateien 13.2 Microsoft Internet Controls 13.2.1 Objektmodell des Webbrowser Control 13.2.2 Anwendungsbeispiele 13.3 Microsoft Common Dialog Control 13.3.1 Objektmodell 13.3.2 Einfaches Beispiel 13.3.3 Öffnen-Dialog 13.3.4 Speichern-Dialog 13.3.5 Schriftarten-Dialog
739 741 742 745 747 748 749 750 751 753 754 756 757
Stichwortverzeichnis
759
Band 2 14 Daten und Dokumente 14.1 ActiveX Data Objects (ADO) 14.1.1 Von ODBC zu OLE DB 14.1.2 Einführung in die ActiveX Data Objects (ADO) 14.1.3 Beschreibung von Datenverbindungen 14.1.4 Das ADO-Objektmodell 14.1.5 Tabellenzugriff mit Recordsets 14.1.6 Befehlsausführung mit der Command-Klasse 14.1.7 Dauerhafte Verbindungen mit der Connection-Klasse 14.1.8 Zugriff auf einzelne Elemente mit der Record-Klasse 14.1.9 Transaktionssteuerung 14.1.10 ADO-Fehlerbehandlung 14.2 SQL Server Distributed Management Objects (DMO) 14.2.1 DMO-Objektmodell 14.2.2 Application-Klasse 14.2.3 SQLServer-Klasse 14.2.4 Anlegen einer neuen Datenbank 14.2.5 Anlegen einer neuen Tabelle 14.2.6 Datensicherung 14.3 DTS-Paketobjekte
791 792 792 796 798 803 805 816 820 822 825 826 828 830 834 835 836 840 842 844
XVII
Inhaltsverzeichnis
14.4 Microsoft Office-Komponenten 14.5 Document Object Model (DOM) 14.5.1 HTML Document Object Model (MSHTML) 14.5.2 XML Document Object Model (MSXML) 14.6 OLE File Property Reader 2.0 (DSOFile) 14.6.1 Klassen 14.6.2 Daten auslesen 14.6.3 Daten ändern 14.6.4 Selbst definierte Eigenschaften 14.6.5 Selbst definierte Eigenschaften löschen 14.7 Microsoft Office-Komponenten 15 Netzwerk und Kommunikation 15.1 Collaboration Data Objects (CDO) 15.1.1 CDO-Grundlagen 15.1.2 CDO-Objektmodell 15.1.3 CDO- und MAPI-Basiskonzepte 15.1.4 CDO-Anmeldung 15.1.5 Zugriff auf Nachrichtenspeicher 15.1.6 Zugriff auf Ordner 15.1.7 Zugriff auf die Nachrichten 15.1.8 Anlegen neuer Nachrichten in Ordnern 15.1.9 Adressbücher und Adresseinträge 15.1.10 Senden einer E-Mail 15.1.11 Arbeit mit Nachrichtenanhängen 15.2 Komponenten für den Exchange Server 2000/2003/2007 15.2.1 Überblick 15.2.2 Exchange-Programmierung mit ADO 15.2.3 CDO 3.0 für Exchange 2000/2003/2007 15.2.4 CDO for Exchange Management 15.3 SMTP-Mail-Komponenten 15.3.1 CDONTS für NT4 15.3.2 CDO for Windows 2000 15.3.3 JMAIL 15.4 Microsoft WinSock-Komponente 15.5 Internet Transfer-Komponente 15.6 ASPInet (FTP) 15.7 Mabry FTPX 15.8 HTTP-Download 15.9 NETCon (Windows Firewall) 15.9.1 Objektmodell 15.9.2 Beispiele
XVIII
846 846 847 854 869 870 871 872 872 873 874 875 876 876 879 883 888 892 893 897 902 904 906 907 909 910 922 943 951 963 964 966 970 972 976 981 982 984 985 986 986
Inhaltsverzeichnis
16 Sicherheitskomponenten 16.1 CAPICOM 16.1.1 Klassen 16.1.2 Verschlüsselung 16.1.3 Hashing 16.2 Scripting Password-Komponente 16.2.1 Klassen 16.2.2 Beispiel 17 Sonstige Scripting-Komponenten 17.1 Reguläre Ausdrücke mit RegExp 17.1.1 RegExp-Objektmodell 17.1.2 Klasse „RegExp“ 17.1.3 Einfacher Mustervergleich mit Test() 17.1.4 RA-Symbole 17.1.5 Ausführlicher Mustervergleich mit Execute() 17.1.6 Submatches 17.1.7 Musterersetzung mit Replace() 17.2 WindowsScripting-Komponente 17.2.1 Klasse „IniFile“ 17.2.2 Klasse „WinNTUser“ 17.2.3 Klasse „Util“ 17.2.4 Klasse „ADSI“ 17.2.5 Klasse „CSV“ 17.3 API-Funktionsaufrufe mit DynaCall 18 Werkzeuge 18.1 Editoren und Entwicklungsumgebungen 18.1.1 Microsoft Visual InterDev 18.1.2 Scripteditor in Microsoft Office 18.1.3 PrimalScript 18.1.4 SystemScripter 18.1.5 OnScript Editor 18.1.6 Visual Basic 6.0 und VB-IDE 18.1.7 Notepad und Notepad Plus 18.1.8 Admin Script Editor (ASE) 18.1.9 VBsEdit/JsEdit 18.1.10 Vergleich der Editoren 18.2 Scriptdebugger 18.2.1 Microsoft Script Debugger 18.2.2 Visual InterDev-Debugger 18.2.3 Visual Basic-Debugger 18.2.4 Andere Debugger 18.3 COM-Werkzeuge 18.3.1 Microsoft Registrierungsdatenbank-Editoren 18.3.2 Registry Crawler
989 989 990 990 991 991 992 992 995 995 996 997 998 999 1001 1004 1005 1006 1007 1008 1009 1009 1010 1010 1013 1013 1013 1016 1016 1019 1022 1023 1023 1024 1025 1025 1027 1027 1028 1029 1029 1029 1029 1030
XIX
Inhaltsverzeichnis
18.4
18.5
18.6
18.7
18.8
18.3.3 Regsvr32, SWBregsvr und CliReg 18.3.4 COM Viewer 18.3.5 COM-Explorer 18.3.6 Dependency Walker 18.3.7 Objektkatalog 18.3.8 comTLBrowser 18.3.9 DCOM-Konfigurationswerkzeug 18.3.10 MTS Explorer 18.3.11 Snap-in „Komponentendienste“ 18.3.12 ROT-Viewer 18.3.13 Scripting Spy 2.11 WMI-Werkzeuge 18.4.1 WMI Object Browser 18.4.2 WMI CIM Studio 18.4.3 WMI Event Registration Tool 18.4.4 WMI Event Viewer 18.4.5 WMI Command Line Utility (WMIC) 18.4.6 WMI Scriptomatic 18.4.7 WMI Code Creator 18.4.8 VBInstance 18.4.9 WMI-Testprogramm 18.4.10 MOF Compiler ADSI-Werkzeuge 18.5.1 MMC-Snap-in „Active Directory-Benutzer und -Computer“ 18.5.2 Active Directory Service Browser (ADB) 18.5.3 ADSI Explorer 18.5.4 ADSI Edit 18.5.5 ADSI Schema Browser 18.5.6 ADSI Scriptomatic MAPI-/CDO-Werkzeuge 18.6.1 Script Director 18.6.2 MAPI Explorer XML-Werkzeuge 18.7.1 XML Notepad 2006 18.7.2 XLST-Transformationen mit MSXSL.EXE 18.7.3 IE Tools for Validating XML and Viewing XSLT Output Sonstige Scripting-Assistenten 18.8.1 HTA Helpomatic 18.8.2 Do-It-Yourself Script Center Kit
1030 1032 1035 1036 1037 1039 1040 1043 1044 1046 1046 1049 1049 1051 1053 1055 1055 1056 1056 1058 1059 1059 1059 1059 1060 1061 1062 1064 1064 1065 1065 1066 1067 1067 1067 1069 1071 1071 1072
19 Fortgeschrittene Active Scripting-Techniken
1073
19.1 Fehlersuche in Scripts (Debugging) 19.1.1 Fehlerarten 19.1.2 Active Scripting-Debugger 19.1.3 Auswahl des Debugger 19.1.4 Aufruf des Debugger 19.1.5 Aktivierung des Debugging
1073 1073 1074 1075 1075 1075
XX
Inhaltsverzeichnis
19.2 Scriptcodierung mit dem Script Encoder 19.2.1 Codierung per Kommandozeile 19.2.2 Codierung per Script mit der Klasse Scripting.Encoder 19.3 Digitale Signaturen für Scripts 19.3.1 Grundlagen digitaler Signaturen 19.3.2 Erstellen von Signaturen mit den CryptoAPI-Werkzeuge 19.3.3 Aktivierung der automatischen Prüfung 19.3.4 Digitale Signaturen und Softwareeinschränkungen 19.3.5 Digitale Signaturen und Scriptcodierung 19.4 Login- und Logoff-Scripts 19.5 Entwicklung von Automatisierungslösungen in Visual Basic 6 19.5.1 VB-EXE versus Scripting 19.5.2 Erstellung einer VB-EXE 19.5.3 Eingabehilfen 19.5.4 Einbindung von Typbibliotheken 19.5.5 Debugging 19.5.6 Eingebaute Objekte (Intrinsic Objects) 19.5.7 Grafische Benutzeroberflächen mit VB-Forms 19.5.8 WSH-kompatible Programmierung in VB 19.6 Die VBA-Hosts in Microsoft Office 19.6.1 Entwicklungsumgebung 19.6.2 Start einer VBA-Routine 19.6.3 Eingebautes Objekt 19.6.4 VBA-UserForms 19.6.5 Microsoft Office Developer Edition 19.7 Prototyping von Exchange Event Agents innerhalb der VB 6.0-IDE 19.8 Erzeugung eigener COM-Komponenten 19.8.1 Erzeugung von Komponenten mit VB 6.0 19.8.2 Windows Script Components (WSCs) 19.9 Ausführung entfernter Scripts 19.9.1 Remote Scripting mit dem WSH 19.9.2 Remote Scripting im Web 19.10 Nutzung entfernter COM-Komponenten 19.10.1 Remote Scripting via DCOM 19.10.2 Remote Scripting mit Windows Script Components (WSCs) 19.10.3 Remote Data Service (RDS) 19.11 Programmierung eigener Scripting Hosts 19.12 Komponentenerforschung 19.12.1 Suche nach Komponenten 19.12.2 Analyse von Komponenten 20 Fallbeispiele 20.1 ADS-Organisationsstrukturwerkzeug 20.1.1 Aufgabenstellung 20.1.2 Lösung
1077 1079 1081 1082 1082 1084 1091 1093 1094 1095 1097 1098 1101 1103 1105 1106 1107 1109 1110 1113 1115 1116 1117 1117 1118 1119 1125 1125 1131 1139 1140 1148 1148 1149 1152 1158 1158 1161 1161 1166 1173 1173 1173 1174
XXI
Inhaltsverzeichnis
20.2 Massenbenutzerimport 20.2.1 Aufgabenstellung 20.2.2 Lösung 20.3 Login-Script 20.3.1 Aufgabenstellung 20.3.2 Lösung 20.4 Scriptfernausführung per E-Mail 20.4.1 Aufgabenstellung 20.4.2 Lösung 20.5 WebPrinterManager 20.5.1 Aufgabenstellung 20.5.2 Lösung 20.6 WBEM Multi Server Disk Viewer (WMSDV) 20.6.1 Aufgabenstellung 20.6.2 Lösung 20.7 Hardware-Inventarisierung 20.7.1 Aufgabenstellung 20.7.2 Lösung 20.8 Dienstestatus 20.8.1 Aufgabenstellung 20.8.2 Lösung 20.9 Dateisystemstrukturdokumentation 20.9.1 Aufgabenstellung 20.9.2 Lösung 20.10 DemoHost 20.10.1 Aufgabenstellung 20.10.2 Lösung 20.11 Weitere Beispiele 20.11.1 ADS-Gruppenwerkzeug 20.11.2 DTS-Anwendung 20.11.3 Character Map Viewer 20.11.4 WebUserManager
Teil C PowerShell 21 .NET Framework 21.1 Was ist das .NET Framework? 21.2 Weitere Eigenschaften des .NET Framework 21.3 .NET-Klassen 21.3.1 Namensgebung von .NET-Klassen (Namensräume) 21.3.2 Namensräume und Softwarekomponenten 21.3.3 Bestandteile einer .NET-Klasse 21.3.4 Vererbung 21.3.5 Schnittstellen 21.3.6 Dokumentation
XXII
1176 1176 1178 1180 1180 1180 1182 1182 1184 1187 1187 1188 1192 1192 1193 1197 1197 1198 1203 1203 1203 1206 1206 1206 1212 1212 1213 1214 1214 1215 1216 1217
1219 1221 1221 1223 1224 1224 1225 1226 1227 1227 1228
Inhaltsverzeichnis
22 Einführung in die Windows PowerShell (PS) 22.1 22.2 22.3 22.4
22.5
22.6
22.7
22.8
Geschichte Bezugsquelle und Installation Architektur Einzelbefehle der PowerShell 22.4.1 Commandlets 22.4.2 Aliase 22.4.3 Ausdrücke 22.4.4 Externe Befehle 22.4.5 Dateinamen Objektorientiertes Pipelining 22.5.1 Grundlagen 22.5.2 Objektorientierung 22.5.3 Analyse des Pipeline-Inhalts 22.5.4 Filtern 22.5.5 Zusammenfassung von Pipeline-Inhalten 22.5.6 Kastrierung von Objekten in der Pipeline 22.5.7 Sortieren 22.5.8 Gruppierung 22.5.9 Berechnungen 22.5.10 Zwischenschritte in der Pipeline 22.5.11 Beispiele Ausgabefunktionen 22.6.1 Standardausgabe 22.6.2 Seitenweise Ausgabe 22.6.3 Einschränkung der Ausgabe 22.6.4 Ausgabe einzelner Werte 22.6.5 Unterdrückung der Ausgabe 22.6.6 Weitere Ausgabefunktionen Navigationsmodell 22.7.1 Provider und Laufwerke 22.7.2 Navigationsbefehle 22.7.3 Pfadangaben 22.7.4 Eigene Laufwerke definieren PowerShell Language (PSL) 22.8.1 Befehlstrennung 22.8.2 Kommentare 22.8.3 Variablen 22.8.4 Zahlen 22.8.5 Zeichenketten 22.8.6 Datum und Uhrzeit 22.8.7 Arrays 22.8.8 Kontrollkonstrukte 22.8.9 PowerShell-Scripts 22.8.10 PowerShell-Scripts als Commandlets verwenden 22.8.11 Commandlets für Script-Ausführung
1229 1229 1230 1231 1231 1232 1234 1239 1239 1239 1239 1239 1240 1242 1249 1250 1251 1251 1252 1253 1253 1254 1255 1257 1257 1257 1259 1260 1260 1261 1262 1262 1263 1263 1264 1264 1264 1265 1266 1266 1269 1270 1270 1272 1273 1275
XXIII
Inhaltsverzeichnis
22.9 Eingabe 22.10 Anbindung an Klassenbibliotheken 22.10.1 WMI-Objekte 22.10.2 .NET- und COM-Objekte 22.11 Sicherheitsfunktionen 22.12 Fehlersuche 22.13 Tipps und Tricks 22.14 Erweitern der PowerShell 22.15 Commandlets von anderen Anbietern 22.16 Ausblick auf PowerShell 2.0 und „Aspen“ 22.17 Weitere Informationen über die PowerShell 22.17.1 Websites zur PowerShell 22.17.2 Weblogs zur PowerShell 23 PowerShell-Werkzeuge 23.1 23.2 23.3 23.4
Powershell-Konsole PowerShell IDE PowerShell Analyzer Weitere Werkzeuge
24 Systemautomatisierung mit der PowerShell 24.1 Dateisystem 24.1.1 Laufwerke 24.1.2 Inhalt eines Verzeichnisses 24.1.3 Dateisystemoperationen 24.1.4 Dateieigenschaften lesen und verändern 24.1.5 Freigaben 24.2 Dokumente und Datenbanken 24.2.1 Textdateien 24.2.2 CSV-Dateien 24.2.3 XML-Dateien 24.2.4 HTML-Dokumente 24.2.5 Relationale Datenbanken 24.3 Registrierungsdatenbank (Registry) 24.4 Computerverwaltung 24.5 Hardwareverwaltung 24.6 Softwareverwaltung 24.7 Prozesse 24.8 Druckerverwaltung 24.9 Systemdienste 24.10 Netzwerk 24.10.1 Ping 24.10.2 Netzwerkonfiguration 24.10.3 Abruf von Daten von einem HTTP-Server
XXIV
1276 1277 1277 1283 1285 1285 1286 1287 1288 1288 1289 1289 1289 1291 1291 1293 1294 1295 1297 1297 1297 1298 1298 1299 1299 1299 1299 1300 1301 1302 1303 1304 1306 1307 1307 1309 1310 1310 1312 1312 1312 1313
Inhaltsverzeichnis
24.11 24.12 24.13 24.14
Ereignisprotokolle Leistungsdaten Exchange Server 2007 Grafische Benutzeroberflächen 24.14.1 Eingabemaske 24.14.2 Universelle Objektdarstellung
25 Verzeichnisdienst-Scripting mit der PowerShell 25.1 Benutzer- und Gruppenverwaltung mit WMI 25.2 Einführung in System.DirectoryServices 25.2.1 Architektur 25.2.2 Objektmodell 25.2.3 Konzeptionelles Chaos bei Microsoft 25.2.4 Überblick über die Programmiermechanismen 25.3 Beispiele zum Active Directory-Scripting 25.4 Kapselung von Verzeichnisdienstfunktionen in eigenen Commandlets
Teil D Anhang
1314 1315 1316 1318 1318 1319 1321 1321 1322 1322 1324 1326 1328 1332 1340
1347
26 Grundlagen objektorientierter Komponentenarchitekturen
1349
26.1 Objektorientierung 26.1.1 Objekte 26.1.2 Schnittstellen (Interfaces) 26.1.3 Klassen 26.1.4 Vererbung (Inheritance) 26.1.5 Beziehungen zwischen Objekten und Klassen 26.1.6 Objektmodelle 26.1.7 Polymorphismus 26.1.8 Dynamische Bindung 26.2 Komponentenarchitekturen 26.3 Marktübersicht
1349 1349 1351 1351 1354 1355 1359 1361 1361 1362 1366
27 Kurzeinführung in XML 27.1 27.2 27.3 27.4 27.5 27.6 27.7 27.8 27.9
Elemente und Attribute Processing Instructions (PIs) Wohlgeformtheit und Gültigkeit Zeichensätze XML-Namensräume Datentypen XML-Beispiele Darstellung von XML-Dokumenten XML und Scripting
1369 1369 1370 1371 1373 1374 1374 1376 1379 1385
XXV
Inhaltsverzeichnis
28 Visual Basic-Funktionen 28.1 28.2 28.3 28.4 28.5 28.6 28.7 28.8 28.9 28.10
Numerische Funktionen Finanzmathematische Funktionen Formatierungsfunktionen String-Funktionen Datum/Uhrzeit Array-Funktionen Funktionen zur Arbeit mit COM Systemfunktionen und Ein-/Ausgabe Typprüfung und -umwandlung Sonstige Funktionen
29 Literaturverzeichnis 29.1 29.2 29.3 29.4 29.5
Gedruckte Literatur Quellen im Internet Requests for Comment (RFCs) Newsgroups Andere Quellenangaben
30 Abkürzungsverzeichnis
XXVI
1387 1387 1388 1389 1390 1391 1392 1392 1393 1395 1397 1399 1399 1402 1409 1410 1411 1413
Teil A Einführung
1
Über den Autor Dr. Holger Schwichtenberg
왘 Studienabschluss Diplom-Wirtschaftsinformatik an der Universität
Essen 왘 Promotion an der Universität Essen im Gebiet komponentenbasier-
ter Softwareentwicklung 왘 Seit 1996 selbstständig als freier Berater, Dozent, Softwarearchitekt 왘 왘 왘 왘
왘 왘
und Fachjournalist 21 Fachbücher bei Addison-Wesley, Microsoft Press und dem WEKA-Verlag Mehr als 350 Beiträge in Fachzeitschriften Ständiger Mitarbeiter der Zeitschriften iX, Windows IT Pro und dotnetpro Regelmäßiger Sprecher auf nationalen und internationalen Fachkonferenzen (z.B. TechEd, OOP, Advanced Developers Conference, Microsoft IT Forum, Wirtschaftsinformatik, Net.Object Days, VS One, Online, Windows Forum, DOTNET-Konferenz, BASTA, XML-in-Action) Dozent für Wirtschaftsinformatik an der Fachhochschule für Oekonomie und Management (FOM) in Essen Zertifikate und Auszeichnungen von Microsoft: 왘 Microsoft Most Valuable Professional (MVP) 왘 Microsoft Certified Solution Developer (MCSD) 왘 .NET Code Wise Community-Experte 왘 Mitglied im weltweiten Codezone Premier Website-Programm
왘 Thematische Schwerpunkte: 왘 objektorientierte Programmiersprachen (C#, Java, Visual Basic .NET u.a.) 왘 .NET Framework 왘 internetbasierte Informationssysteme/Webanwendungen (insbesondere ASP.NET) 왘 Scripting und automatisierte Systemadministration 왘 Microsoft Windows Client und Server
3
1 Über den Autor Dr. Holger Schwichtenberg
왘 Ehrenamtliche Community-Tätigkeiten: 왘 Vorstandsmitglied bei codezone.de 왘 Sprecher für die International .NET Association (INETA) 왘 Betrieb der Community-Websites www.dotnetframework.de und
www.windows-scripting.de 왘 Firmen-Website: 왘 http://www.IT-Visions.de 왘 Weblog: 왘 http://www.dotnet-doktor.de (bei Heise.de) 왘 Kontakt: 왘
[email protected]
4
2
Vorwort
Damit Sie etwas Einblick in die Geschichte dieses Buchs (und damit der Windows Scripting-Technologien) erhalten, finden Sie in diesem Kapitel nicht nur das Vorwort zur aktuellen Auflage, sondern auch Ausschnitte aus den Vorwörtern der vorherigen Auflagen.
2.1
Vorwort zur 5. Auflage
Liebe Leserinnen und Leser, mit der fünften Auflage ist dieses Buch nun endgültig ein Klassiker im IT-Fachbuchmarkt. Zu Verdanken ist diese Langlebigkeit neben den Verkäufen natürlich auch der (für Microsoft ungewöhnlichen) Technologiekontinuität. Der Windows Script Host (WSH) arbeitet auch in Windows Vista nach dem gleichen Grundkonzept wie in Windows 2000. Seitdem sind natürlich viele Bibliotheken hinzugekommen (Scripting-Komponenten), die dem »alten« WSH-Scripting immer neue Möglichkeiten eröffnen. Die Nachfolgetechnologie – die Microsoft PowerShell – erreicht in diesen Tagen das Produktionsstadium der Version 1.0. Die PowerShell basiert nicht mehr auf COM, sondern auf dem .NET Framework und setzt neue Maßstäbe in Hinblick auf Kompaktheit und Einfachheit. Veränderungen an diesem Buch Die zweite bis vierte Auflage dieses Buchs beschäftigten sich ausführlich mit dem .NET Framework und den in der .NET-Klassenbibliothek enthaltenen Funktionen zur automatisierten Systemadministration. Die Microsoft PowerShell basiert zwar auf dem .NET Framework, abstrahiert jedoch von vielen Mechanismen dieser Laufzeitumgebung. Die Auseinandersetzung mit .NET ist daher in dieser Auflage auf die für die PowerShell-Nutzung notwendigen Teile beschränkt. Mehr aktuelles Wissen zu .NET finden Sie in meinem Buch .NET 2.0 Crashkurs [SCH08]. Den gewonnenen Freiraum in diesem Buch nutze ich für die Aufnahme folgender Themen: Neue 왘 Zugriff auf Daten und Dokumente mit ADO, DMO, MSHTML, MSXML und OLE File 왘 왘 왘 왘
Themen
Property Reader Netzwerkkonfiguration mit WMI Windows Remote Management (WinRM) Kommunikation via TCP/IP, SMTP und HTTP Zugriff auf Microsoft Exchange mit CDO und CDOEXM
5
2 Vorwort
왘 Nutzung regulärer Ausdrücke (RegExp) 왘 Verschlüsselung und Hashing mit CAPICOM 왘 Steuerung mit Windows Firewall mit NETCon 왘 Weitere Scripting-Werkzeuge (insbesondere Assistenten/Codegeneratoren) 왘 Remote Scripting mit Windows Script Components (WSCs) 왘 Neuerungen in Windows Vista
FAQ Weitere Informationen über Zielgruppe und Aufbau dieses Buchs sowie den Inhalt der beiliegenden CD-ROM finden Sie in Form eines FAQ im Anschluss an das Vorwort. Dank- Dank Im Rahmen dieser Auflage möchte ich meinen besonderen Dank aussprechen an: sagungen
왘 die Korrektorinnen Petra Kienle und Astrid Schürmann, die abwechselnd in den bis-
herigen Auflagen meine Tippfehler gefunden und sprachliche Ungenauigkeiten eliminiert haben, 왘 meine Lektorin Sylvia Hasselbach, die dieses Buchprojekt seit sieben Jahren bei Addison-Wesley betreut, 왘 alle Leser, die mit ihrem Feedback zu den bisherigen Auflagen dazu beigetragen haben, dass dieses Buch immer besser wurde. LeserWebsite
Feedback Ich freue mich wieder über Feedback zu dieser Auflage und werde dieses bei der nächsten Neuauflage berücksichtigen. Nutzen Sie dazu bitte die Leser-Website: http://www.windows-scripting.de/leser Dort existieren auch Foren für Fragen zu den Themen dieses Buchs. Darüber hinaus steht Ihnen meine E-Mail-Adresse
[email protected] für Anfragen zu Projektunterstützung und Schulungen zur Verfügung. Holger Schwichtenberg Essen, im November 2006
2.2
Auszug aus dem Vorwort zur 4. Auflage (2004)
… Sie halten die vierte Auflage von „Windows Scripting“ in Händen, die im Januar 2005 – zwei Jahre nach der dritten Auflage – erscheint. Zwar hat Microsoft inzwischen keine neue Version des Windows Script Host (WSH) veröffentlicht, aber es gibt mittlerweile neue Komponenten und Werkzeuge für das Scripting. Außerdem ist diese Neuauflage um viele anschauliche Beispiele ergänzt worden. Neue Kapitel
Veränderungen an diesem Buch Neu in dieser Auflage sind insbesondere Kapitel zu den folgenden Themen: 왘 Scripting von Gruppenrichtlinien mit der GPO-Komponente 왘 Scripting des Microsoft Exchange Server 2003
6
Auszug aus dem Vorwort zur 3. Auflage (2002)
왘 Die Microsoft Shell (MSH) als kommender Nachfolger des WSH 왘 Script-Werkzeuge (SystemScripter, OnScript, Scriptomatic etc.)
Erheblich erweitert wurden die Kapitel über: 왘 Active Directory Service Interface (ADSI) und
Stark erweiterte Kapitel
왘 Windows Management Instrumentation (WMI)
Das Buch ist um über 150 Seiten angewachsen. Aus drucktechnischen Gründen hat AddisonWesley daher die Papierstärke etwas verringert. Alle Kapitel aus den vorherigen Auflagen sind in aktualisierter Form erhalten geblieben; lediglich das Kapitel über den Exchange Server 5.5 ist aus Platzmangel entfernt worden. … Gliederung des Buchs Die Erfahrungen seit Erscheinen des .NET Framework haben gezeigt, dass viele Unternehmen den Schritt von COM zu .NET nicht oder nur sehr zögerlich vollziehen. Die Neuauflage dieses Buchs trägt dem Rechnung, indem das COM- und das .NET-basierte Scripting durch zwei Buchteile (A und B) voneinander getrennt werden. Sie haben so die Möglichkeit, die Teile unabhängig voneinander zu studieren und zu praktizieren. In jedem Buchteil finden Sie die methodisch klare Trennung zwischen: 왘 den Grundlagen des Softwarekomponentenmodells, 왘 den Script-/Programmiersprachen 왘 den Ablaufumgebungen (Hosts) 왘 den nutzbaren Softwarekomponenten 왘 sinnvollen Werkzeugen 왘 fortgeschrittenem Wissen und 왘 Fallbeispielen
Den beiden Teilen ist eine Einführung vorangestellt, die Ihnen einen Überblick über die Möglichkeiten der automatisierten Systemadministration gibt. Holger Schwichtenberg Essen, im November 2004
2.3
Auszug aus dem Vorwort zur 3. Auflage (2002)
[…] 6000 verkaufte Exemplare in zwei Jahren und der kontinuierliche Platz als Bestseller unter Motivation den Scripting-Büchern bei Amazon.de haben mich sehr erfreut. Gerne hätte ich mich bei meinen Lesern mit einer um 400 zusätzliche Seiten erweiterten 3. Auflage bedankt – genug Material schlummert auf meinem Fileserver. Aus wirtschaftlichen und produktionstechnischen Gründen sind der Ausdehnung eines Werks leider Grenzen gesetzt. Auf den ersten Blick hat die 3. Auflage nur 130 Seiten mehr als die vorherige Auflage, auf den zweiten Blick werden Sie jedoch feststellen, dass durch einen geänderten Satzspiegel erheblich mehr Inhalt auf den gleichen Raum gedruckt werden konnte. […]
7
2 Vorwort
Was neu ist Seit den ersten beiden Auflagen dieses Buchs in den Jahren 2000 und 2001 hat sich im Bereich des Windows Scripting eine Menge getan. WMI
Die Windows Management Instrumentation (WMI) ist viel mächtiger geworden und bietet neben der Abfrage von Systeminformationen auch immer mehr Möglichkeiten der Veränderung von Einstellungen. Daneben gibt es eine Vielzahl neuer spezialisierter COM-Komponenten, die abgegrenzte Bereiche besser und (noch) mächtiger ansteuern können als die Allround-Komponente WMI.
.NET Framework
Mit dem .NET Framework hat Microsoft inzwischen eine neue Programmierplattform veröffentlicht, die nicht nur für „große“ Anwendungen, sondern auch für „kleine“ Scripts neue Möglichkeiten bietet. Dementsprechend hat das .NET Framework mehr Raum in diesem Buch bekommen.
Hilfe zur Selbsthilfe
WMI & Co. bieten dennoch weit mehr, als in diesem Buch explizit erwähnt werden kann. Umso wichtiger sehe ich meinen Ansatz, Ihnen das Handwerk zur Selbsthilfe zu vermitteln. Referenztabellen finden Sie in diesem Buch nur selten. Vielmehr versuche ich Ihnen zu vermitteln, wie Sie selbst die Objekte, die Attribute, die Methoden und die notwendigen Parameter finden. Trotzdem bietet die 3. Auflage vor allem mehr Beispiele. Besonders die Bereiche ADSI, WMI und .NET Framework wurden ausgebaut mit vielen Scripts aus dem Bereich Benutzerverwaltung, Computerverwaltung, Netzwerkkonfiguration, Zugriff auf die Registrierungsdatenbank, Dateisystemverwaltung, Druckerverwaltung, Leistungsdatenerfassung und Softwareinstallation. Diese Scripts bieten Ihnen einen idealen Ausgangspunkt für Ihre individuellen Scriptinglösungen. […] Weiterführende Literatur Das „COM-Komponenten-Handbuch“ kann ich Ihnen als Ergänzung zu diesem Buch nahe legen: Dort werden zahlreiche weitere Klassen behandelt, die Ihnen das Leben als Administrator oder systemnaher Softwareentwickler leichter machen. Wenn Sie lieber weiter mit dem .NET Framework arbeiten wollen, dann gibt es für Sie mit dem Buch „Programmieren mit der .NET-Klassenbibliothek“ auch schon die richtige Antwort. Gerade mit dem .NET Framework sind die Möglichkeiten der automatisierten Systemadministration noch vielfältiger geworden. Das Windows Scripting-Buch entwickelt sich immer mehr zu einem Nachschlagewerk, das einen systematischen und weniger einen didaktischen Aufbau hat. Daher finden Sie z.B. die Darstellung aller relevanten Werkzeuge vereint in einem Kapitel, statt verstreut über das ganze Buch. Wenn Sie einen didaktischen Aufbau bevorzugen, habe ich auch eine Lösung für Sie: „Windows Scripting Lernen“ ist ein weiteres Buch mit didaktischer Aufbereitung für Einsteiger, das Ende des Jahres 2002 bei Addison-Wesley erscheinen wird. Leser-Website Über Ihr Feedback freue ich mich auf der Leser-Website http://www. Windows-Scripting.de/Leser. Sofern Fehler in diesem Buch gefunden werden, werden diese dort dokumentiert. Ergänzungen und Änderungen in den Programmbeispielen finden Sie im Download-Bereich. Auf der Leser-Website können Sie auch Ihre Meinung zu diesem Buch abgeben und verbliebene Fragen in ein Diskussionsforum setzen. Die 2. Auflage hat sich in Rekordzeit verkauft. Ich hoffe, auch diese 3. Auflage kommt so gut bei Ihnen an. Holger Schwichtenberg Essen-Byfang im Oktober 2002
8
Auszug aus dem Vorwort zur 2. Auflage (2001)
2.4
Auszug aus dem Vorwort zur 2. Auflage (2001)
Im Juli 2000 ist mein Buch „Windows- und BackOffice-Scripting“ erschienen. Die guten Verkaufszahlen und das durchweg positive Feedback in Rezensionen und in zahlreichen E-Mails von Lesern haben mich motiviert, das Buch schon nach weniger als einem Jahr zu aktualisieren und erheblich zu erweitern. Microsoft hat seit dem Erscheinen von „Windows- und BackOffice-Scripting“ nicht nur einige neue Scripting Hosts und einige neue COM-Komponenten veröffentlicht, sondern mit .NET (sprich „DOTNET“) ein völlig neues Programmierkonzept vorgestellt. Der Themenkomplex Scripting/Automatisierte Administration ist dadurch so umfangreich geworden, dass mein Buch vom Umfang her aus der Bindung geplatzt wäre. Die Lösung dieser Herausforderung lag darin, zwei Bücher daraus zu machen, die beide ihren etwas eigenen Weg gehen: 왘 Das Buch „Windows-Scripting“ umfasst weiterhin alles um das Active Scripting. Das
Alles rund
Buch habe ich erweitert um die aktuelle Version des Windows Scripting Host (WSH 5.6), um das Scripting den SQL Server 2000, den Exchange Server 2000 und den neuen Microsoft Operations Manager (MOM) 2000. Neu sind auch die Themen Remote Scripting, digitale Signierung von Scripts und das Prototyping für Exchange Ereignis-Scripts. Ebenso berücksichtigt sind die Änderungen in Windows Whistler (Windows XP und Windows .NET Server) sowie neue COM- und Scripting-Werkzeuge. Völlig neu ist auch ein umfangreiches Kapitel zu Microsoft .NET. Das .NET Framework .NET wird nicht nur die Arbeit der Softwareentwickler, sondern auch die Arbeit der Administratoren verändern. Das Kapitel behandelt die Grundlagen der .NET-Laufzeitumgebung und liefert Beispiele in Visual Basic.NET. Bezüglich der COM-Komponenten beschränkt sich dieses Buch jetzt auf die Kernkomponenten für das Scripting (WSHRuntime, FSO, ADSI, WMI und WSHController).
왘 Parallel dazu erscheint als Auskopplung das Buch „COM-Komponentenhandbuch“. Die-
Kompo-
ses Buch stellt eine Vielzahl von existierenden COM-Komponenten von Microsoft und nenten anderen Anbietern dar. Gegenüber dem Komponententeil des alten Buchs ist es aktualisiert und erweitert: ADO 2.7, CDO 3.0, CDO for Exchange Management, MSXML 4 sowie das Common Dialog Control und die OnePoint-Komponenten des Microsoft Operations Manager (MOM). Das Komponentenhandbuch ist die ideale Ergänzung zu diesem Scripting-Buch – sowohl für Administratoren als auch Softwareentwickler. Bestimmte Redundanzen zwischen beiden Büchern sind jedoch notwendig, damit jedes der beiden Bücher auch für sich allein ein abgeschlossenes Werk ergibt. […]
Viel Spaß und Erfolg mit diesem Buch wünscht Ihnen Holger Schwichtenberg Essen, im August 2001
9
2 Vorwort
2.5
Auszug aus dem Vorwort zur 1. Auflage (2000)
[…] Motivation
Mussten Sie schon einmal einhundert NT-User gleichzeitig einrichten? Sollen nach der Benutzeranmeldung bestimmte Aktionen automatisch ausgeführt werden? Haben Sie tagtäglich Dateien zu aktualisieren? Dann sollten Sie das komponentenbasierte Active Scripting (kennen) lernen! Aus meiner Praxis als Administrator einer Farm von NT-basierten (Internet-)Servern weiß ich einerseits die funktionale Benutzeroberfläche von Windows zu schätzen und kenne andererseits den Bedarf nach Automatisierung. Leider hat Microsoft die Automatisierung administrativer Aufgaben in seinen Betriebssystemen und Anwendungen lange Zeit kaum unterstützt. Mit Active Scripts beschäftige ich mich intensiv seit den Anfängen dieser noch jungen Microsoft-Technologie und ich habe mich stets darüber geärgert, dass es in der Fachliteratur nur einige isolierte Darstellungen von ASP, DHTML und dem WSH gab. Unberücksichtigt blieben die zahlreichen anderen Scripting Hosts und die gemeinsame Basis aller Scripting Hosts, die es möglich macht, Scripts und Komponenten zwischen verschiedenen Umgebungen auszutauschen. Der Windows Script Host (WSH) hat unter Windows-Nutzern (nicht zuletzt durch den Love-Letter-Virus) eine gewisse Bekanntheit erreicht; selbst viele Windows-Profis wissen aber nicht, dass der WSH nur einer von vielen Scripting Hosts ist. Nach einer Serie von Veröffentlichungen in der iX habe ich mich dazu entschlossen, selbst das erste Buch zu schreiben, das die breite Palette der Automatisierungsmöglichkeiten auf Basis von Scripts und Komponenten dokumentiert. Sie finden in diesem Buch daher zahlreiche verschiedene Scripting Hosts und werden lernen, die für Ihre Automatisierungsaufgabe passende Umgebung auszuwählen.
10
COM
Was dieses Buch erreichen will Da die gesamte Scripting-Architektur auf dem Component Object Model (COM) basiert, ist COM ein zentrales Thema in diesem Buch. Man kann unter Windows Scripts erstellen, ohne COM zu verstehen; wenn man aber die Grundgedanken von COM und die in Komponenten gekapselten (Meta-)Objektmodelle versteht, dann eröffnen sich zusätzliche Möglichkeiten. Selbst wenn Sie schon Scripts geschrieben haben, werden die ersten beiden Kapitel dieses Buchs bei Ihnen eine Serie von Groschen fallen lassen.
Komponenten
Sie finden in diesem Buch eine interessante Auswahl von Komponenten für die Erstellung von Automatisierungslösungen unter Windows NT, 9x und Windows 2000 sowie für die Microsoft Backoffice-Produkte. Systematisch werde ich Ihnen die Grundideen und Anwendungsgebiete jeder einzelnen Komponente darlegen. Durch grafische Darstellung der Objektmodelle und insgesamt über 500 Codebeispiele werde ich die Arbeitsweise der Komponenten erläutern. Viele Scripts in diesem Buch sind didaktischer Natur: Sie sind bewusst kurz gehalten und fokussieren auf einen bestimmten Aspekt. Das ermöglicht ein besseres Erlernen der Techniken als Mammut-Beispiele, die zwar viel Funktionalität bieten, aber schwer durchschaubar sind. Umfangreiche Automatisierungslösungen, die auf dem Zusammenspiel mehrerer Komponenten beruhen, finden Sie in Kapitel 10 „Fallbeispiele“.
Auszug aus dem Feedback zu den bisherigen Auflagen
Dieses Buch ist jedoch keine vollständige Referenz für die einzelnen Komponenten und nicht zu jedem Attribut oder jeder Methode gibt es ein Beispiel. Viele der hier vorgestellten Komponenten sind so umfangreich, dass eine Referenz ein eigenes 1000-seitiges Buch füllen würde. Der Schwerpunkt dieses Buchs liegt vielmehr darauf, Ihnen Hilfe zur Selbsthilfe zu geben: Auf Hilfe zur einem Markt, auf dem fast täglich neue Softwarekomponenten erscheinen, ist es wichtiger, Selbsthilfe ein Grundverständnis für die Technologie zu entwickeln, als Ihnen eine Referenz für Komponenten zu liefern, welche sowieso ständig aktualisiert werden. Dieses Buch zeigt zu jeder Komponente die Anwendungsmöglichkeiten auf und liefert Ihnen einen Einstieg, so dass Sie nachher mit beiden Beinen fest in der Materie stehen. Wenn Sie ganz in einer Komponente versinken möchten, dann sind das Studium der MSDN-Entwicklerbibliothek bzw. der jeweiligen Dokumentation des Herstellers und eine intensive Recherche im Web unerlässlich. Gehören Sie zu den Leuten, die nicht gerne in die MSDN-Entwicklerbibliothek schauen, so wird Ihnen dieses Buch den Weg dorthin ebnen. Zusätzlich liefert Ihnen Kapitel 6 ein Vorgehensmodell zur Suche und Erforschung von Komponenten. Das Buch spannt einen Bogen zwischen dem echten Scripting und der Erstellung von Auto- VB und VBA matisierungslösungen auf Basis von kompilierten Visual Basic-Anwendungen und selbst erstellten COM-Komponenten. Daher wird dieses Buch nicht nur VBScript behandeln, sondern Ihnen auch VBA und die Visual Basic-Vollversion näher bringen. […] Holger Schwichtenberg Essen, im Juli 2000
2.6
Auszug aus dem Feedback zu den bisherigen Auflagen
Mit diesem umfangreichen Werk – gut 1000 Seiten plus weitere Informationen auf der beiliegenden CD-ROM – hat Holger Schwichtenberg so etwas wie eine „Skripting-Bibel“ für den Systemadministrator geschrieben. Gut gegliedert und umfassend beschrieben kann das Buch sowohl als Einführungskurs in die Script-Programmierung für den Systemverwalter als auch – wie bei uns in der Redaktion – als Nachschlagewerk für viele Fragen im Zusammenhang mit Skripting und COM (Component Object Model) dienen. Gerade die ausführliche Behandlung von COM/DCOM und COM+ ist es, die dieses Buch von anderen Werken abhebt. Ein sehr empfehlenswertes Werk für Systemadministratoren, die ihre Windows-Systeme mittels Skripting verwalten wollen. Rezension in Windows 2000-Magazin, Ausgabe 09/2002 Das Buch ist eine wertvolle Ressource für alle, die Windows NT4- und Windows 2000-Systeme verwalten müssen. Es liefert überdurchschnittlich viel Know-how und bereitet das Wissen sehr strukturiert und verständlich auf. Darüber hinaus ist es ein hervorragendes Nachschlagewerk, wenn es um COM-Details oder den Einsatz der enthaltenen Komponenten geht. Ein vergleichbares Werk, das eine so große Anzahl von Komponenten übersichtlich und detailliert behandelt,
11
2 Vorwort
ist in deutscher Sprache sonst nicht erhältlich. Dadurch wird es auch für Programmierer interessant, die „nur“ Visual Basic nutzen und keine Administrationsaufgaben haben. Rezension in BasicPro – Das Fachmagazin für Basic-Profis, Ausgabe 4/2000 Wer Windows-Server und -Workstations administriert, kommt an Windows-Scripting kaum vorbei. Man spürt die praktische Erfahrung des Autors, ebenso wie seine journalistische Erfahrung. Frank Müller (Amazon.de) Nachdem ich zuerst „Windows-Scripting-Lernen“ 2. Auflage gelesen hatte, habe ich mir dieses Buch gekauft. Der Preis ist zwar hoch, aber das Buch ist sein Geld wert. Über 1000 Skripte werden mit dem Buch (auch auf CD) mitgeliefert. Während andere Bücher einfach nur ein paar Skripte aufdrucken und Zeile für Zeile erklären, findet man hier die Hintergründe, z.B. wie genau GetObject und CreateObject funktionieren. Der Autor ist auch nicht sparsam mit Kritik an Microsoft. Immer wieder zeigt er auf, wo Microsoft es dem Admin unnötig schwer macht. Das Buch war sehr hilfreich für mich, um zu erkennen, was die Regeln und was die Ausnahmen beim Scripting Host sind. Der Autor ist ein sehr bekannter Scripting-Experte, den ich auch schon mal auf einem Windows-Forum als engagierten Dozenten erlebt habe. Rezensentin/Rezensent bei Amazon.de Ich hatte mir schon die 2. Auflage gekauft und ich bereue es nicht, nochmal die 60 Euro für die dritte Auflage ausgegeben zu haben. Ich bin wieder begeistert. Fast 1200 Seiten voller Infos zum Scripting. Im Gegensatz zu Konkurrenzwerken werden hier auch die Hintergründe erklärt, so dass man sich nachher in ADSI, WMI und anderen Klassen wirklich zurecht findet. … Zudem gibt der Autor auf seiner Website für seine Leser einen erstklassigen Support, wenn man sich dort registriert. Rezensentin/Rezensent bei Amazon.de Wow – wenn es nur mehr so Bücher gäbe... Nach wenigen Seiten wird einem klar, dass man hier übersichtlich und absolut verständlich quer durch die aktuellen COM-Komponenten geführt wird. Eine Leserin oder ein Leser aus Feldkirch (Österreich), bei Amazon.de Nach der ersten Durchsicht Ihres Buchs kann ich nur sagen: SEHR GUT! Vergleichbares habe ich weder auf dem deutschen noch englischsprachigen Markt gefunden! Ein Meilenstein, der hoffentlich allen Scripting-Ignoranten die Augen öffnen wird! Thomas Sohnrey (GE CompuNet, Frankfurt), per E-Mail Zu groß, zu dick, zu viel drin! Was andere in mehreren Büchern unterbringen, findet man hier endlich mal zusammengefasst in knapp 1000 Seiten. Das Buch gehört zu den Besten, die ich bisher gelesen habe!
[email protected], bei Amazon.de
12
Auszug aus dem Feedback zu den bisherigen Auflagen
Geniales Buch für professionelles Scripting. Der Autor bringt die Sachen verständlich auf den Punkt. Trotzdem sind es 950 Seiten – in dem Buch steht verdammt viel drin! Rezensentin/Rezensent bei Amazon.de So wie bei den Kleinkindern beginnt man ja auch mit kleinen Schritten, dasselbe habe ich bei Ihrem Buch entdeckt und als das erste Script funktionierte, war die Begeisterung noch viel größer. Loreto Di Salvatore (MPK, Zürich), per E-Mail In dieser Konstellation einzigartiges Buch, welches ausgenommen von Grundlagen, ein sehr breites Know-how vermittelt. Der Stil ist sehr fachlich orientiert und vermeidet weitgehend inhaltslose Passagen. Die einzelnen Kapitel vermeiden geschickt den zusammenhaltslosen Aufbau vieler anderer Bücher. Ein Leser in der Leserumfrage auf www.windows-scripting.de Sehr gute Übersicht + Hintergrundinfo zu den einzelnen Themen; Hervorragend strukturiert! gut visualisiert! Grundlegende Beispiele für jedes Modul geben guten Einstieg. Ein Leser in der Leserumfrage auf www.windows-scripting.de Sehr übersichtlich, das einzige seiner Art (in Deutsch), auch für Einsteiger gut geeignet, sehr gut erklärende Grafiken. Ein Leser in der Leserumfrage auf www.windows-scripting.de Sehr gute Einleitung, guter Aufbau der Themen. Der Einstieg ins Scripting gelingt einfach und trotzdem kann man sich sehr viel Backgroundinformationen holen. Ein Leser in der Leserumfrage auf www.windows-scripting.de Viele verschiedene Themen und immer ein kleines Beispiel dazu leicht verständlich und nicht vom Thema abschweifend Ein Leser in der Leserumfrage auf www.windows-scripting.de Ich finde das Buch verständlich und auch für nicht Profi-Programmierer geeignet. Ohne jedoch in die Banalität abzugleiten. Ein Leser in der Leserumfrage auf www.windows-scripting.de Verständliche und dennoch praxisnahe Beispiele, die sich leicht für eigene Bedürfnisse anpassen lassen. Ein Leser in der Leserumfrage auf www.windows-scripting.de
13
2 Vorwort
Ich habe „Windows Scripting lernen“ (gelesen) und „Windows Scripting“ (bin am durcharbeiten) von Ihnen. Auch habe ich mir das COM Komponenten-Handbuch bestellt. Vielen Dank für die KLASSE Bücher. Das beste, was es gibt. Thorsten Losinski, per E-Mail
14
3
Leser-Portal (Dienstleistungen für Leser nach dem Kauf)
Den Lesern dieses Buches werden vom Autor folgende Serviceleistungen im Rahmen einer zugangsbeschränkten Leser-Portal-Website angeboten: 왘 Downloads: Die Programmcodebeispiele aus diesem Buch werden bei Bedarf aktuali-
왘
왘 왘 왘
siert und erweitert. Laden Sie im Leser-Portal Aktualisierungen des Programmcodes herunter. Diskussionsrunde: Ein webbasiertes Forum bietet die Möglichkeit, Fragen an den Autor zu stellen. Bitte beachten Sie jedoch, dass dies eine freiwillige Leistung des Autors ist und kein Anspruch auf eine kostenlose Betreuung besteht. Newsletter: Alle registrierten Leser erhalten mehrmals jährlich einen Newsletter mit aktuellen Terminen und Publikationshinweisen. Leser-Bewertung: Geben Sie Noten für dieses Buch und lesen Sie nach, was andere Leser von diesem Buch halten. Errata: Trotz eines erprobten Vorgehensmodells und der mehrfachen Qualitätskontrolle ist es möglich, dass sich einzelne Fehler in dieses Buch eingeschlichen haben. Im Webportal können Sie nachlesen, welche Fehler gefunden wurden. Sie können hier auch selbst Fehler melden, die Ihnen auffallen.
Zugang zum Leser-Portal Die WWW-Adresse für den Zugang zum Leser-Portal lautet: http://www.IT-Visions.de/leser Bei der Anmeldung müssen Sie das Losungswort LOST angeben. Sie erhalten dann per E-Mail Ihr persönliches Zugangskennwort, mit dem Sie das Leser-Portal betreten und verwenden können.
15
4
Fragen und Antworten zu diesem Buch (FAQ)
Dieses Kapitel liefert Informationen über dieses Buch in Frage-Antwort-Form. Es beantwortet im Vorfeld viele Fragen, die dem Autor zu anderen Buchprojekten gestellt wurden, und enthält Informationen, die sonst üblicherweise Teil des Vorworts sind.
4.1
Fragen zum Inhalt des Buchs
4.1.1
Wer ist die Zielgruppe dieses Buchs?
Zielgruppen dieses Buchs sind 왘 System- und Netzwerkadministratoren in Unternehmensnetzwerken jeglicher Größe, 왘 Softwareentwickler, die primär mit klassischem Visual Basic arbeiten, 왘 fortgeschrittene Endanwender.
4.1.2
Welche Kenntnisse werden in diesem Buch vorausgesetzt?
Sie sollten Vorkenntnisse in zwei Gebieten mitbringen, um dieses Buch effektiv einsetzen zu können: 왘 Grundlegende Programmierkenntnisse in einer beliebigen Programmiersprache sind
vorteilhaft, da dieses Buch nicht den Raum bietet, die Grundzüge des Programmierens und der Realisierung von Standardalgorithmen zu erläutern. Sie müssen allerdings nicht Visual Basic bzw. VBScript beherrschen, denn diese Sprachfamilie wird ausführlich vorgestellt. 왘 Zum zweiten sollten Sie die Installation und Administration von Windows beherrschen. Das Buch setzt an dem Punkt an, an dem Sie die Administration dieser Umgebungen verinnerlicht haben und nunmehr durch (Script-)Programmierung mehr erreichen möchten.
17
4 Fragen und Antworten zu diesem Buch (FAQ)
4.1.3
Woher kann ich diese Grundlagenkenntnisse bekommen?
Eine Einführung für Administratoren ohne Programmierkenntnisse bietet das Werk „Windows Scripting lernen“ an, das ebenfalls bei Addison-Wesley erschienen ist. Aktuell ist die 2. Auflage, im Frühjahr 2007 wird die dritte Auflage erscheinen.
4.1.4
Für wen ist dieses Buch nicht geeignet?
Das Buch ist nicht geeignet für Personen, die eine Schritt-für-Schritt-Anleitung („KlickAnleitung“) benötigen und keinerlei Vorkenntnisse in der Programmierung („Was ist eine Variable?“) besitzen. Personen, die bereits über jahrelange Erfahrung mit Windows Scripting verfügen, können dieses Buch allenfalls als punktuelle Referenz bzw. Einarbeitung in die PowerShell einsetzen.
4.1.5
Was ist der Schwerpunkt dieses Buchs?
Das Buch ist ein Nachschlagewerk für die Erstellung und den Aufbau von Scripting-Lösungen. Zielsetzung dieses Buchs ist es, Ihnen Hilfe zur Selbsthilfe zu geben. Sie werden daher sehr viel über den Aufbau der verschiedenen Scripting-Umgebungen und Softwarekomponenten sowie über deren Einsatzgebiete erfahren. Selbstverständlich enthält dieses Buch auch zahlreiche Codebeispiele (in dieser Auflage sind es insgesamt über 1000). Viele Beispiele können Sie direkt in Ihren Automatisierungslösungen einsetzen. Bei anderen Beispielen steht im Vordergrund, Ihr Verständnis für die Technologie zu schärfen. Dieses Buch verwendet durchgängig die in Windows am weitesten verbreitete Programmier- und Scriptsprache Visual Basic – genauer gesagt, die Dialekte Visual Basic Script 5.6 und Visual Basic 6.0. Für in der Programmierung wenig erfahrene Personen stellt diese Sprache den leichtesten Zugang zur automatisierten Systemadministration dar. Bei „Windows Scripting“ handelt es sich also um ein konzeptionelles Nachschlagewerk, weil dieses Buch keine vollständige Referenz aller Scripting-Klassen und deren Attribute und Methoden enthält. Inzwischen existieren über 10.000 Klassen mit über 100.000 Attributen/ Methoden. Diese hinreichend zu behandeln, geht weit über das Ansinnen dieses Buchs hinaus; ein Buch wäre dafür auch nicht das geeignete Medium.
4.1.6
Was bedeutet der Titel der Buchreihe „net.com“?
Nachdem die erste Auflage in der „BackOffice“-Reihe und die zweite sowie die dritte in der so genannten „WinTec“-Reihe erschienen sind, hat „Windows Scripting“ seit der vierten Auflage seinen Platz in einer Reihe gefunden, die sich „net.com“ nennt. Das ist eine treffende Zuordnung, weil dieses Buch sowohl das .NET Framework als auch das Component Object Model (COM) behandelt – wenngleich der eigentliche Hintergrund des Reihennamens die Wörter „network“ und „communication“ sind.
18
Fragen zum Inhalt des Buchs
4.1.7
Wie positioniert sich dieses Buch zu Ihren anderen Büchern?
„Windows Scripting“ steht zwischen den Büchern „Windows Scripting lernen“ und „Programmieren mit der .NET-Klassenbibliothek“. Das Buch „Windows Scripting lernen“ richtet sich an Scripting-Einsteiger ohne Vorerfahrung in der Programmierung. Danach sollte man „Windows Scripting“ lesen. Das Buch „Programmieren mit der .NET-Klassenbibliothek“ kann als Aufbauliteratur verwendet werden, um die Möglichkeiten der Microsoft PowerShell besser zu nutzen. Das Buch „COM-Komponenten-Handbuch“, das im Jahr 2000 als eine Abspaltung dieses Buchs entstanden ist, wurde von mir aus Zeitgründen nicht mehr weiterentwickelt. Die 5. Auflage von „Windows Scripting“ umfasst nahezu alle Themen, die auch im „COMKomponenten-Handbuch“ enthalten sind. Titel
Zielgruppe
Windows Scripting lernen Administratoren ohne 2. Auflage Programmierkenntnisse Holger Schwichtenberg et al. 461 Seiten ISBN 3-8273-2170-1 Januar 2003
Windows Scripting 5. Auflage Holger Schwichtenberg 1300 Seiten ISBN 3-8273-2423-8 Februar 2007
Tabelle 4.1: Die Produktfamilie der Windows ScriptingBücher bei AddisonWesley
Adminstratoren mit Programmierkenntnissen Visual BasicSoftwareentwickler
19
4 Fragen und Antworten zu diesem Buch (FAQ)
4.1.8
Titel
Zielgruppe
Programmierung mit der .NET-Klassenbibliothek 2. Auflage Frank Eller, Holger Schwichtenberg 1129 Seiten ISBN 3-8273-2128-2 September 2003
.NET-Softwareentwickler PowerShell-Nutzer Fortgeschrittene Scriptentwickler
Finde ich in diesem Buch Informationen, die es nicht in der MSDN-Bibliothek gibt?
Bitte kaufen Sie dieses Buch nicht, wenn Sie der Meinung sind, dass die MSDN-Entwicklerbibliothek eine Informationsquelle ist, in der Sie schnell alles finden, was Sie brauchen. In diesem Buch stehen nur wenige Dinge, die Sie nicht auch irgendwo in den mehreren hunderttausend Seiten der MSDN-Entwicklerbibliothek finden können. Tatsächlich gibt es fast keine Bücher zu Microsoft-Technologien, die Themen behandeln, die nicht auch durch die MSDN-Bibliothek abgedeckt sind, denn ein Buch kann natürlich auf rund 1000 Seiten nicht den Inhalt der MSDN-Bibliothek überbieten. Dieses Buch bietet Informationen in einer anderen Form. Komprimiert, praxisnäher und selektiver. Sie brauchen dieses Buch, wenn Sie nicht die Zeit haben, lange in der MSDN-Bibliothek zu suchen und sich durch lange Texte zu arbeiten, aber komprimierte und praxisnahe Informationen aus einer Hand zu schätzen wissen.
4.1.9
Woher beziehen Sie Informationen, die Sie in diesem Buch niederschreiben?
Erste Informationen zu neuen Microsoft-Produkten erhalte ich meist auf Veranstaltungen von Microsoft (sowohl öffentliche Entwicklerveranstaltungen wie die Professional Developer Conference und der TechEd als auch „interne“ Veranstaltungen) oder durch Dokumente, die mir Microsoft im Rahmen des MVP-Programms zur Verfügung stellt. Weitere Informationsquellen sind darüber hinaus die MSDN-Entwicklerbibliothek, Artikel auf Websites, Weblogs und Newsgroups. Meine wichtigste Informationsquelle sind aber eigene Erfahrungen, die ich mit dem Produkt sammle. In früheren Produktstadien sind es meist nur kleinere Testanwendungen. In der Beta-Phase entwickle ich oft bereits Lösungen für „mutige“ Kunden, die dann bald nach dem endgültigen Veröffentlichungstermin des Produkts in auslieferungsfertige Lösungen münden. Bücher anderer Autoren stehen mir meist nicht zur Verfügung, weil ich viele Bücher schon zu einem frühen Produktstadium beginne.
20
Fragen zum Inhalt des Buchs
4.1.10
Warum lassen Sie manche Details aus?
Windows Scripting ist ein komplexes und sehr umfangreiches Thema. Ich schätze, für eine komplette Darstellung des Themas müsste man ca. 8000 Seiten schreiben. Folglich musste ich auswählen, welche Themen in das Buch kommen und welche nicht. Die Seitenzahl eines Buchs lässt sich leider aus betriebswirtschaftlichen und produktionstechnischen Gründen nicht unbegrenzt nach oben erweitern.
4.1.11
Wie treffen Sie die Entscheidung, welche Themen in das Buch kommen und welche nicht?
Die Entscheidung, welche Themen ich in das Buch nehme und welche nicht, basieren auf vier Punkten: 왘 meine eigene Projekterfahrung, welche Funktionen man braucht und welche nicht 왘 meine Erfahrung, welche Funktionen Kunden einsetzen, die ich bei der Nutzung von
Windows-Technologien berate 왘 Nachfragen von Schulungsteilnehmern und Vortragszuhörern 왘 Auswertung des Feedbacks zu vorherigen Büchern auf der Leser-Website
4.1.12
Sind Teile des Buchs aus anderen Büchern übernommen?
Ein kleiner Teil dieses Buchs ist aus dem „COM-Komponentenhandbuch“ entnommen. Sie benötigen das „COM-Komponentenhandbuch“ nicht als Zusatzliteratur.
4.1.13
Wie sollte ich dieses Buch lesen?
Es besteht keine Notwendigkeit, dieses Buch sequentiell zu lesen. Auf unvermeidliche Lesehilfe Abhängigkeiten zwischen den Kapiteln möchte ich aber hinweisen. Allen Lesern empfehle ich die Lektüre der Buch-FAQ (Kapitel 4 in Buchteil A) sowie des Einführungskapitels (Kapitel 5). Kapitel 6 und 21 konzentrieren sich auf die Theorie zu COM und .NET. Die Theorie sollte Sie nicht abschrecken, da sie sehr viele konzeptionelle Grundlagen zum Verständnis der restlichen Kapitel enthält. Die Kapitel über die Sprachsyntax von Visual Basic (Kapitel 8) sollten Sie nur dann über- Teil B springen, wenn Sie schon viel in dem jeweiligen Visual Basic-Dialekt programmiert haben. Die Reihenfolge, in der Sie die Kapitel zu den einzelnen Scripting Hosts (Kapitel 3), zu Softwarekomponenten (10 bis 17) und Werkzeugen (18) lesen, können Sie frei wählen, da jedes dieser Unterkapitel in sich abgeschlossen ist. Die Auseinandersetzung mit den fortgeschrittenen Techniken (Kapitel 19) setzt die Lektüre der vorhergehenden Kapitel voraus. Die Kapitel zur PowerShell (Buchteil C, Kapitel 21 bis 25) können Sie unabhängig vom Teil C Buchteil B lesen.
21
4 Fragen und Antworten zu diesem Buch (FAQ)
Anhang
Bitte beachten Sie auch den Anhang: Dort finden Sie eine Einführung in das objektorientierte Programmieren und in die Softwarekomponentenarchitekturen, eine Liste der Visual Basic-Funktionen sowie einige hilfreiche Erläuterungen zu den in diesem Buch verwendeten (Sprach-)Konventionen und zur grafischen Notation.
4.2
Fragen zu den sprachlichen Konventionen
4.2.1
Wie halten Sie es mit Anglizismen?
Ich versuche, Anglizismen zu vermeiden. Dies bedeutet zum Beispiel, dass ich Schaltfläche statt Button, Zwischenspeicher statt Cache, entfernter Computer statt Remotecomputer, Performanz oder Leistung statt Performance und Protokollierung statt Logging verwende. Begriffe habe ich nicht immer wörtlich, sondern zum Teil sinngemäß übersetzt. In Fällen, wo englische Begriffe sehr etabliert sind (z.B. Client, Server, Scripting) und die deutschen Übersetzungen kaum verständlich wären, bleibe ich bei den englischen Begriffen. Auch Produktbezeichnungen (z.B. Microsoft SQL Server) und Technologiekonzepte (z.B. Programmatic Identifier) übersetze ich nicht.
4.2.2
Wie grenzen Sie die Windows-Versionen sprachlich ab?
Um nicht immer wieder alle relevanten Windows-Versionen aufzählen zu müssen, verwendet das Buch folgende sprachlichen Abkürzungen: NT
왘 Die Verwendung des Begriffs „Windows NT“ oder einfach „NT“ umfasst auch – sofern
nicht anders erwähnt – später erschienene, auf NT basierende Betriebssysteme, also Windows 2000, Windows XP, Windows Server 2003, Windows Vista und Windows Server Codename „Longhorn“. Die Betriebssystennamen sind nur Marketingbegriffe. Intern verstehen sich die Betriebssysteme als NT 5.0, 5.1, 5.2 und 6.0. Windows 9x
왘 Windows 9x steht für Windows 95 und Windows 98. Windows 9x/ME schließt auch
Windows ME mit ein.
4.2.3
Wie grenzen Sie die verschiedenen Visual BasicDialekte und Versionen voneinander ab?
Bezüglich der Visual Basic-Sprachfamilie werden folgende Sprachregelungen angewandt: VB VB 6.0
왘 Visual Basic (oder kurz „VB“) wird als Oberbegriff für die Sprachfamilie verwendet. 왘 Die Bezeichnung VB-Vollversion wird für die kompilierungsfähige Programmiersprache
im Rahmen von Visual Studio 98 verwendet. VB 6.0 bezeichnet die Version 6.0. VB.NET
왘 Wie üblich, wird Visual Basic .NET mit VB.NET abgekürzt. Visual Basic .NET (alias
VB.NET) wird auch für die Version 8.0 verwendet, die nicht Visual Basic .NET 2005, sondern nur Visual Basic 2005 heißt, da diese Version trotzdem auf .NET basiert.
22
Fragen zur Gestaltung des Buchs
왘 Das Kürzel VBA steht für Visual Basic for Applications, die in Microsoft Office und
VBA
anderen Produkten enthaltene Makrosprache. 왘 Die Ausdrücke Visual Basic Script, VBScript und VBS bezeichnen die nichtkompilierte
VBS
(also interpretierte) Scriptsprache.
4.2.4
Wie grenzen Sie die Begriffe Automation und Automatisierung ab?
Automation und Automatisierung: Die Abgrenzung dieser beiden Begriffe ist bei vielen Autoren unklar. Einerseits verstehen Autoren darunter die Durchführung administrativer Aufgaben durch Programme, andererseits stehen die Begriffe für ein spezielles Verfahren innerhalb des Component Object Model (COM). Dabei sind diese Bedeutungen keineswegs gleichzusetzen. In diesem Buch wird das COM-Verfahren stets Automation, der allgemeine Begriff jedoch Automatisierung genannt. Zwar ist COM-Automation ein Hilfsmittel zur Automatisierung, aber keineswegs das einzige.
4.2.5
Automation versus Automatisierung
Was bedeutet MINFU?
Sie werden in diesem Buch hin und wieder eine Ihnen sicherlich bisher nicht bekannte Buch- MINFU stabenkombination finden: MINFU. MINFU steht für MIcrosoft Nomenclature Foul-Up und bezeichnet Fälle, in denen Microsoft Probleme mit der adäquaten Benennung der eigenen Produkte und Konzepte hat. Urheber dieses Begriffs ist der amerikanische Autor David S. Platt, der sich um die Aufnahme von MINFU als Wort in das Oxford English Dictionary (OED) bemüht. Jede Verwendung von MINFU bringt ihn ein Stückchen näher an die Verewigung im OED.
4.3
Fragen zur Gestaltung des Buchs
4.3.1
Wie werden die Informationen in diesem Buch dargestellt?
Wann immer sinnvoll und möglich, erfolgt die Darstellung in diesem Buch in Grafiken, Auflistungen und Tabellen. Tendenziell wird auf umfangreichen Fließtext zugunsten dieser Darstellungsformen verzichtet.
4.3.2
Welche Formatierungen kommen in diesem Buch zum Einsatz?
Quellcode sowie die Namen von Klassen, Schnittstellen, Attributen, Methoden und Ereig- Hinweise zur Formanissen erkennen Sie an der nichtproportionalen Schrift. In kursiver proportionaler Schrift finden Sie Textausgaben von Scripts.
tierung des Textes
Kursiv gesetzt sind Namen und Werte, sofern der Begriff aus mehreren Wörtern besteht und es zu Missverständnissen kommen könnte, welche Wörter zu dem Begriff gehören. Oft wird
23
4 Fragen und Antworten zu diesem Buch (FAQ)
ein Begriff nur bei der ersten Verwendung kursiv geschrieben. Fett geschrieben sind Wörter, die besonders betont werden sollen. Ebenfalls in kursiv finden Sie jegliche Form von Ressourcenpfaden, also Dateinamen, Dateipfade, URLs und Moniker sowie alle Namen, die Bildschirmelementen entsprechen (z.B. Registerkarten, Menüeinträge, Schaltflächen). Wichtige Hinweise und Einschübe sind durch einen grauen Kasten hinterlegt. Zusätzlich werden vier Symbole verwendet, um Ihre Aufmerksamkeit zu wecken: Warnung vor Fehlern oder möglichen Schwierigkeiten
Interessante Hintergrundinformationen
Verweis auf die dem Buch beiliegende CD-ROM
Tipp
4.3.3
Sind die Bildschirmabbildungen in diesem Buch in Deutsch oder Englisch?
Aus verschiedenen Gründen sind in diesem Buch die Bildschirmabbildungen gemischt. Einerseits gibt es viele Scripting-Werkzeuge nicht in einer deutschen Version. Andererseits habe ich beim Entstehen der ersten Auflagen dieses Buchs noch deutsche Versionen bei der täglichen Arbeit verwendet. Inzwischen nutze ich – wie viele meiner Kunden übrigens auch – nur noch englische Versionen, weil 왘 viele Aktualisierungen schneller für die englischen Systeme verfügbar sind, 왘 einige Erweiterungen gar nicht in deutschen Versionen laufen, 왘 die deutschen Übersetzungen (insbesondere der Dokumentation) so schlecht sind, dass
sie die Produktivität mit den Systemen beinträchtigen.
4.3.4
Welche grafische Notation verwenden Sie in den Objektdiagrammen?
Grafische Eine wichtige Leistung dieses Buchs ist es, Ihnen zu den Komponenten grafische DarstellunNotation in gen der Objektmodelle in Form von Objektdiagrammen an die Hand zu geben, die es ermögden Objektdiagrammen lichen, die grundsätzliche Navigation im Objektmodell einer Komponente wesentlich schnel-
ler zu erfassen als mit einer textlichen Beschreibung.
24
Fragen zur Gestaltung des Buchs
Da die Objektmodelle oft sehr umfangreich und die Navigationspfade komplex sind, beschränkt sich die Darstellung in der Regel auf die wichtigsten Klassen und deren Zusammenhänge. Die Objektmodelle stellen die typische Hierarchie der Objekte zur Laufzeit dar, nicht die Ver- Objekterbungshierarchie der Klassen. Allerdings müssen nicht alle in den Objektmodellen modelle dargestellten Beziehungen zu jedem Zeitpunkt existieren. Die Darstellung ist die abstrakte Darstellung möglicher Beziehungen (vgl. Kapitel 7 „Das Component Object Model“). KannBeziehungen werden von Muss-Beziehungen in der grafischen Notation nicht unterschieden. Als Notation wurde bewusst nicht die Unified Modeling Language (UML) gewählt, sondern eine eigene Notation, die sich an der üblichen Microsoft-Dokumentation orientiert und in diesem speziellen Fall wesentlich übersichtlicher ist als UML. Bild 4.1: Grafische Elemente zur Darstellung von Objektdiagrammen
Klasse B "Komponente.Klasse" Get_E()
Klasse E
Klasse D (Collection)
Klasse A Klasse C Attribut_xy
Komponente. Klasse X
Ein Objektdiagramm ist ein Graph mit Knoten und Kanten. Die Knoten sind Klassen oder Grundsätzelementare Datentypen, die hier als geometrische Formen dargestellt werden. Die Kanten licher Aufbau drücken Beziehungen zwischen den Klassen/Datentypen aus; sie sind als Verbindungslinien in Form von Pfeilen dargestellt. Bemerkungen sind als Sprechblasen mit schwarzem Hintergrund dargestellt. Klassenname
IName1
Klassenname
IName2
Name Einzelklasse Klassenname "ProgID" Extern instanziierbare Klasse
Collection-Klasse Klassenname Instanzen dieser Klasse gelten als persistent
Attribut enthält Objektzeiger
Elementarer Datentyp Klassenname (Objektname) Bestimmte Instanz einer Klasse
Methode liefert Objektzeiger
Klassenname
Klasse unter expliziter Nennung von Schnittstellen Objektname [Intrinsic Object]
Intrinsic Object
1-zu-1-Beziehung
Klasse
Bild 4.2: Beispiel für die grafische Darstellung eines Objektmodells in diesem Buch
Klasse aus anderer Komponente
1-zu-n-Beziehung
25
4 Fragen und Antworten zu diesem Buch (FAQ)
Knoten (geometrische Formen) In den Objektdiagrammen werden folgende Bausteine als Knoten verwendet: 왘 Einfache Klassen sind als Ovale dargestellt. 왘 Objektmengen (Collection/Container) sind dagegen in Form von Rechtecken dargestellt. 왘 Elementare Datentypen (z.B. Zeichenketten, Zahlen) sind Dreiecke.
Sofern eine Klasse in einem Objektmodell mehrfach eingezeichnet ist, bedeutet dies, dass Instanzen dieser Klasse in verschiedenen Zusammenhängen vorkommen können. Allerdings bedeutet das im Umkehrschluss nicht, dass mehrere Verweise auf ein und den gleichen grafischen Baustein immer ein und die gleiche Instanz repräsentieren. Zusätze In den Knoten können folgende Zusätze vorkommen: 왘 Sofern ein Oval, ein Rechteck oder ein abgerundetes Rechteck eine gestrichelte Umran-
dung haben, bedeutet dies, dass die Klasse bzw. die Schnittstellen nicht in dieser, sondern in einer anderen Komponente definiert ist bzw. sind. Es gibt also eine Verbindung zu einem anderen Objektmodell. Der Name ist dann in der Form Komponente.Klassen name bzw. Klasse::Komponente.Schnittstellenname angegeben. Schatten
왘 Eine mit einem Schatten hinterlegte Klasse ist eine von außen instanziierbare COM-
Klasse. Alle anderen Klassen können nur von anderen Klassen der Komponente erzeugt werden. Unterstreichung
왘 Bei Klassen, deren Klassenname unterstrichen ist, ist es möglich, auf einzelne Instanzen
Eckige Klammern
왘 Eingebaute Objekte sind mit dem in eckigen Klammern stehenden Zusatz [Intrinsic
Runde Klammern
왘 Namen in runden Klammern hinter dem Klassennamen bezeichnen eine einzelne, kon-
Anführungszeichen
왘 Namen in Anführungszeichen sind von dem Klassennamen abweichende Program-
Bullet&Stick
왘 Sofern alle Mitglieder der Klasse über eine Standardschnittstelle mit IDispatch-Unter-
direkt über COM-Moniker zuzugreifen. Object] versehen. krete Instanz dieser Klasse (also ein Objekt) mit dem in runden Klammern angegebenen Namen. Der Name einer Instanz ist in der Regel nur dann angegeben, wenn es nur eine einzige Instanz dieser Klasse gibt. matic Identifier, die im HKEY_CLASSES_ROOT registriert sind. stützung angeboten werden, sind Schnittstellen nicht explizit eingezeichnet. In einigen wenigen Fällen, in denen die Mehrfachschnittstellen auch bei der Scriptprogrammierung von Bedeutung sind, sind diese in der üblichen Bullet&Stick-Form an Klassen angehängt.
Icons
왘 Die Objektdiagramme von Verzeichnisdienstobjektmodellen sind mit zusätzlichen
Symbolen versehen, die nur der Illustration dienen und keine inhaltliche Bedeutung haben.
26
Fragen zur Gestaltung des Buchs
In einigen Fällen sind in den Objektdiagrammen Klassen eingezeichnet, obwohl es sich auf der Implementierungsebene um Schnittstellen von ein und derselben Klasse handelt. Aus der Sicht von Visual Basic und den Scriptsprachen gibt es jedoch keine Schnittstellen, sondern nur Klassen. Da dieses Buch sich aber auf das Rapid Application Development (RAD) konzentriert, mögen die C++-Programmierer es verzeihen, wenn die Dokumentation der Objektmodelle an einigen Stellen nicht ihren Bedürfnissen entspricht. Kanten (Verbindungslinien) Die Kanten stellen Nutzungsbeziehungen auf Basis von Kanten Attributen oder Methoden dar. Die Kanten sind als gerichtete Pfeile dargestellt, wobei der Pfeil immer bei der Klasse beginnt, in der das Attribut bzw. die Methode implementiert ist. Die Pfeilspitze weist auf die Klassen, deren Instanz von dem Attribut oder der Methode als Ergebnis geliefert wird. Die Notation unterscheidet nicht zwischen Assoziationen und Aggregationen, da Letztere zum einen sehr selten vorkommen und sich zum anderen von der Nutzung her nicht von den Assoziationen unterscheiden. Verbindungslinien stellen Nutzungsbeziehungen dar. Die Notation unterscheidet allerdings zwischen dem Zugriff über ein Attribut und dem über eine Methode.
Attributzugriff versus Methodenzugriff
Nutzungsbeziehungen auf Basis von Attributen Die durchgezogenen Pfeile sind Nutzungsbeziehungen auf Basis von Attributen: 왘 Ein durchgezogener Pfeil von einem Oval zu einem Rechteck bedeutet, dass eine Klasse
eine Objektmenge enthält. Sofern diese Linie nicht beschriftet ist, ist die Objektmenge über ein Attribut der Klasse erreichbar, das genauso heißt wie die Objektmenge. Heißt das Attribut anders, steht der Attributname als Beschriftung an der Linie. 왘 Ein durchgezogener Pfeil von einem Rechteck zu einem Oval bedeutet, dass eine Objektmenge aus Objekten der im Oval genannten Klasse besteht. Hier erfolgt üblicherweise der Zugriff auf die untergeordneten Objekte über das Attribut Item; nur wenn dies nicht zutrifft, ist das Attribut explizit angegeben. Auch in den Fällen, in denen Item als Methode implementiert ist, wird konsistent eine durchgezogene Linie verwendet. 왘 Ein durchgezogener Pfeil von einem Rechteck zu einem Dreieck bedeutet, dass eine Objektmenge aus Werten eines elementaren Datentyps besteht. 왘 Ein durchgezogener Pfeil von einer Klasse zu einer anderen Klasse bedeutet, dass eine Instanz der übergeordneten Klasse genau ein Unterobjekt der untergeordneten Klasse erhalten wird. Auch hier erfolgt die Angabe des Attributs nur, wenn dies nicht gleich dem Klassennamen ist. Von Klassen, die Objektmengen repräsentieren, können Pfeile mit einer doppelten Pfeilspitze ausgehen. Dies bedeutet, dass die Objektmenge n Unterobjekte dieser Klasse enthalten kann (1-zu-n-Beziehung). Eine einfache Pfeilspitze ist die Beschränkung auf eine Instanz (1-zu-1Beziehung). Sind an dem Pfeil allerdings mehrere Attribut- bzw. Methodennamen genannt, so kann jedes der genannten Attribute eine andere Instanz liefern.
27
4 Fragen und Antworten zu diesem Buch (FAQ)
Bild 4.3: Modellierung der Nutzungsbeziehungen mit verschiedenen Kardinalitäten in COM
1-zu-1-Beziehung Klasse A
1-zu-n-Beziehung
n-zu-m-Beziehung Klasse A
Klasse A Klasse B
Collection C
Collection C
Klasse B
Klasse B
Collection D
Bild 4.4: Unterscheidung zwischen homogener und heterogener Collection
Homogene Objektmenge
Heterogene Objektmenge Objekt (Klasse A)
Objekt (Klasse A)
Objektmenge
Objektmenge
Objekt (Klasse B)
Objekt (Klasse D)
Objekt (Klasse E)
Objekt (Klasse F)
Gestrichelte Linien
Nutzungsbeziehungen auf Basis von Methoden Gestrichelte Pfeile sind Zugriffspfade auf Basis von Methodenaufrufen. Eine gestrichelte Linie mit der Beschriftung MName() bedeutet, dass ein Aufruf der Methode MName() auf einer Instanz der Ausgangsklasse eine Instanz der Klasse liefert, auf die die Spitze des Pfeils zeigt. Der Methodenname ist aus Gründen der Übersichtlichkeit ohne Parameterliste angegeben. Nicht dargestellt sind Nutzungsbeziehungen auf Basis von Methodenaufrufen, die als Parameter eine Instanz einer bestimmten Klasse erwarten. 왘 Eine gestrichelte Linie, die nicht bei einem Objekt beginnt, sondern aus dem leeren
Raum kommt, bedeutet, dass der Zugriff über eine in einer Komponente definierte globale Methode erfolgt, die nach Einbindung der Komponente global zur Verfügung steht. 왘 Sofern der Weg von Instanzen einer Klasse zu Instanzen anderer Klassen auf mehreren Wegen beschritten werden kann, sind die Attribut- bzw. Methodennamen durch Kommata getrennt als Beschriftung der Linie angegeben. Im Normalfall beziehen sich alle genannten Attribute bzw. Methoden auf eine andere Instanz der Zielklasse. Sofern es sich um einen Verweis auf ein und dieselbe Instanz handelt, sind die synonymen Attribute und Methoden in Klammern gesetzt. Gabelung
28
Weitere Hinweise Eine sich gabelnde Linie bedeutet, dass das Attribut bzw. die Methode Instanzen verschiedener Klassen zurückliefern kann.
Fragen zur Gestaltung des Buchs
4.3.5
Wie vollständig sind die Objektdiagramme?
Auf eine vollständige Auflistung aller Attribute, Methoden und Ereignisse innerhalb der VollständigGrafiken wurde bewusst verzichtet, da diese sonst sehr unübersichtlich geworden wären. keit Mitglieder sind in Form der Verbindungslinien nur insofern dargestellt, als sie Zeiger auf andere Objekte zurückliefern und damit das Objektmodell bestimmen. Hinweise zu weiteren Attributen, Methoden und Ereignissen finden Sie im Text oder in der MSDN-Dokumentation.
4.3.6
Was bedeutet es, wenn hinter einem Wort ein leeres Klammernpaar steht?
Methodennamen werden stets – unabhängig von der Parameteranzahl – durch ein Klammernpaar „()“ kenntlich gemacht und damit von Attributnamen abgegrenzt. Bitte beachten Sie aber, dass Visual Basic die Verwendung von Klammern nur bei Funktionen und Methoden mit Rückgabewert zulässt. Nur in Visual Basic .NET sind die Klammern immer zu setzen.
4.3.7
Wieso verweisen Sie bei Querverweisen nur auf Themen, nicht aber direkt auf die Kapitelnummer?
Der Grund für die Verweise auf Namen anstelle von Kapitel- oder Seitennummern liegt Keine darin, dass ein umfangreiches Buch wie dieses zunächst in verschiedenen Word-Dokumen- genauen Verweise ten erstellt und anschließend mit Framemaker gesetzt wird. In diesem Produktionsprozess ist es laut Aussage der DTP-Experten nicht möglich, kapitelübergreifende Querverweise, die man in Word gesetzt hat, zu erhalten. In den ersten beiden Auflagen zu diesem Buch hatte sich der Autor sehr viel Mühe mit den Probleme Querverweisen gegeben und musste dann leider feststellen, dass diese beim Satz des Buchs beim Satz völlig durcheinander gekommen waren. In mühevoller Arbeit haben dann die Lektorin und der Autor in der Satzfahne die fehlerhaften Querverweise von Hand verbessert. Sie können sich wahrscheinlich gut vorstellen, dass dies bei einem so umfangreichen Buch nicht nur sehr mühsam ist, sondern dass auch leicht Fehler übersehen werden. Daher habe ich mich ab der 3. Auflage entschlossen, entweder nur auf Oberkapitelnummern oder auf Kapitelnamen zu verweisen. Soweit möglich, habe ich die Verweise auf naheliegende Elemente durch relative Verweise („siehe nächste Abbildung“, „siehe die folgenden beiden Tabellen“) ersetzt. Das bedeutet für Sie zwar etwas mehr Mühe, das entsprechende Unterkapitel mithilfe des Inhaltsverzeichnisses oder des Stichwortverzeichnisses ausfindig zu machen, doch halte ich dies für die bessere Alternative, als Sie mit falschen Querverweisen in die Irre zu führen. Umso mehr Arbeit habe ich in das Stichwortverzeichnis investiert.
Stichwortverzeichnis
29
4 Fragen und Antworten zu diesem Buch (FAQ)
4.4
Fragen zur Buch-CD-ROM
4.4.1
Was befindet sich auf der CD-ROM?
Die diesem Buch beiliegende CD-ROM enthält folgende Verzeichnisse: \CODE
Das Verzeichnis enthält alle Programmbeispiele aus dem Buch, geordnet nach Programmiersprachen (insbes. VBScript, VB 6.0 und PowerShell) und Kapiteln. Die Kapitel 10 bis 17 sind nach Komponenten unterteilt. Der auf der CD enthaltene Code für Visual Basic .NET stammt aus der 2. bis 4. Auflage und ist in dieser Auflage des Buchs weder im Buch abgedruckt noch dokumentiert.
\INSTALL
Erweiterungen, Komponenten, Sprachen und Werkzeuge für das Windows Scripting (zum Teil als Vollversionen, zum Teil als Demoversionen). Dieses Verzeichnis ist nach Kapiteln (in denen das Programm besprochen wurde) und Produktnamen weiter untergliedert. Das \INSTALL-Verzeichnis enthält zum Teil auch .REG-Dateien und Scripts, die im Buch beschriebene Änderungen an der Registrierungsdatenbank durchführen.
\KONSTANTEN-
Bei der Besprechung einiger Komponenten wird Bezug auf Konstantenlisten genommen, die sich auf Grund ihrer Größe nicht für den Abdruck im Buch geeignet haben. Diese finden Sie als Textdateien in diesem Verzeichnis.
LISTEN
30
\UMGEBUNG
Dieses Verzeichnis enthält Dateien, die von einigen Scripts als Arbeitsdateien verwendet werden. In vielen Scripts haben diese Dateien immer den Pfad D:\BUCH. Kopieren Sie die Dateien dieses Verzeichnisses vorzugsweise auch nach D:\BUCH auf Ihre Festplatte. Andernfalls müssen Sie die Pfade in den Scripts anpassen.
\WEBSITE_ZUM_ BUCH
Hier finden Sie eine HTML-Datei, die Ihnen sagt, wie Sie sich in dem geschützten Leserbereich auf der Website zu diesem Buch anmelden können.
\WEITERE_ INFORMATIONEN
Dieses Verzeichnis enthält das ActiveX Scripting FAQ von Mark M. Baker, die Microsoft VBScript-Dokumentation, das Portable Script Center und eine HTML-Seite mit WWW-Links.
Fragen zur Buch-CD-ROM
4.4.2
Wie finde ich die Codebeispiele auf der Begleit-CD-ROM wieder?
Alle größeren Listings sind auf der CD-ROM im Verzeichnis \CODE enthalten. In der Regel finden Sie unter dem Listing eine eckige Klammer, die auf den Namen einer WSH-Datei (Erweiterung .VBS oder .WSF ) verweist, die das Script enthält. Der genaue Pfad ist nicht angegeben, sofern er sich aus der Verzeichnisstruktur der CD-ROM ergibt, die der Kapitelstruktur des Buchs entspricht. Die Kapitelnamen sind auf der CD-ROM aber zumeist abgekürzt. Bild 4.5: Ausschnitt aus der Verzeichnisstruktur der Codebeispiele auf der CDROM (hier: VBScriptLösungen für das Active DirectoryScripting mit der ADSIKomponente)
Hilfsroutine und Bibliotheken Innerhalb eines jeden Unterkapitels gibt es noch einen Ordner /HILFSROUTINEN, der die zu diesem Thema vorgestellten Hilfsroutinen in einer Datei mit dem Namen [KAPITELKURZNAME]_HELPER.VBS enthält. Jedes Script bindet diese Datei ein, unabhängig davon, welche Hilfsroutinen wirklich für das Script verwendet werden. Außerdem bindet jedes Script die Bibliotheken WS_scriptLIB (siehe Kapitel 8.18) und WS_vbwshLIB (siehe Kapitel 19.5.8) ein. Die Bibliotheken sind zum Teil mehrfach auf der CD-ROM enthalten (Verzeichnisse /_BIBLIOTHEKEN).
31
4 Fragen und Antworten zu diesem Buch (FAQ)
Codebeispiele im VB 6.0-Projekt Die Beispiele der Kapitel 10 bis 17 sind zusätzlich im Rahmen eines Visual Basic-Projekts (.VBP) zusammengefasst, das Sie im Unterverzeichnis /CODE_VB6/ des jeweiligen Kapitels finden. Das VB-Projekt ist in Module gegliedert, die den Unterkapiteln entsprechen. Einige Scripte, die besondere Funktionen des WSH oder des IE nutzen (z.B. die Ereignisbehandlung), sind nicht im VB-Projekt enthalten. Diese Scripte beginnen mit einem Unterstrich „_“. Sie können die Scripte innerhalb von Visual Basic 6.0 mithilfe des Direktfensters einzeln starten, indem Sie den Namen der Unterroutine im Direktfenster eingeben (in der nachstehenden Abbildung ist dies WMI_Dienstzustand_Umkehren).
Bild 4.6: Komfortables Editieren und Starten der Beispiele in der Visual Basic 6.0-Entwicklungsumgebung
32
Fragen zu den Programmcodebeispielen
4.4.3
Was kann ich tun, wenn die CD-ROM zu meinem Buch fehlt oder defekt ist?
Schreiben Sie in diesem Fall bitte eine E-Mail an den Verlag:
[email protected]
4.5
Fragen zu den Programmcodebeispielen
4.5.1
Warum gibt es in diesem Buch nur Beispielcode in Visual Basic Script und nicht auch in JavaScript (JScript)?
Visual Basic Script (VBS) ist die bei weitem am meisten eingesetzte Scriptsprache in der Windows-Welt. Die meisten Beispiele von Microsoft sind in VBScript geschrieben. Einige Werkzeuge unterstützen nur VBS. JavaScript (JScript) ist wichtig für das Browser-Scripting, jedoch unbedeutend für die Automatisierung von administrativen Aufgaben in Windows. Zitat von Microsoft: „VBScript will always remain our primary focus simply because most Windows administrators who write system administration scripts use VBScript… If our focus had been on something other than system administration (for example, if we focused on scripting for Web developers) we likely would have taken a different tack.“ [MSDN56]
4.5.2
Nach welchen Richtlinien erstellen Sie Codebeispiele?
Ich verwende auf Basis meiner Erfahrung und auf Basis von Leser-Feedback folgende Richtlinien bezüglich der Programmcodebeispiele in diesem Buch: 왘 Die Beispiele sollen möglichst autonom sein, d.h., ein abgedrucktes Listing soll alle not-
왘
왘
왘
왘
wendigen Elemente enthalten, auch wenn dies auf Kosten der Wiederverwendung von Programmcode geht. Alle notwendigen Konfigurationsinformationen (z.B. Computernamen, Verbindungszeichenfolgen) sollen Teil des Listings sein, auch wenn dies dazu führt, dass diese Daten im Quelltext statt in einer Konfigurationsdatei abgelegt werden. Beispiele sollen dann nicht autonom sein, wenn es explizit darum geht, die Wiederverwendbarkeit von Programmcode, die Nutzung von Konfigurationsdateien oder eine gute Softwarearchitektur darzustellen. Die Variablennamen in den Codebeispielen sollen einfach sein. Kurznamen, die nur aus einem oder zwei Buchstaben stehen, sind entgegen den üblichen Gepflogenheiten erlaubt, um Platz zu sparen und Zeilenumbrüche in abgedruckten Listings zu vermeiden (dies erhöht die Lesbarkeit von Listings in einem Buch!). Bei allen Codebeispielen steht die Funktionalität im Vordergrund, nicht die Gestaltung der Ein- und Ausgabe.
33
4 Fragen und Antworten zu diesem Buch (FAQ)
Variablennamen
Variablennamen Aus Platzgründen wurde in den Listings in diesem Buch auf lange Variablennamen verzichtet. Die Listings sind in der Regel so kurz, dass dies nicht zu Nachteilen bei der Lesbarkeit führt. Für Laufvariablen wurden einbuchstabige Namen wie a, b, x und y verwendet. Namen für Objektvariablen sind meist Abkürzungen der Klassennamen, wobei das Präfix obj oder o vorangestellt wurde. Sofern der Klassenname nicht eindeutig ist, werden auch o und obj als einzelne Variablen verwendet. Namen für Objektmengen (Collections) beginnen häufig mit dem Präfix col.
Deklaratio- Deklarationen und Typisierung In den meisten Listings sind die Variablen mit Dim nen und deklariert und es ist als Kommentar der Datentyp in der VB-Form („As xy“) angegeben. Sie Datentypen
können zwar diese Typisierung in VBScript nicht nutzen, jedoch unterstützt der Hinweis auf den Datentyp das Verständnis der Listings. Außerdem haben Sie es so leichter, die Scripts von der Buch-CD in typisierten Umgebungen wie VB 6.0, VB.NET und VBA zu verwenden.
Konstanten
Konstanten In der Regel werden in den Listings numerische Konstanten verwendet und die zugehörigen symbolischen Konstanten nur als Kommentar angegeben. Dies ermöglicht es, dass die Scripts auch ohne Einbindung einer Typbibliothek lauffähig sind, zumal noch nicht alle Scripting Hosts die Einbindung von Typbibliotheken erlauben. Variablendeklarationen erfolgen grundsätzlich ohne Typdefinitionen, da dies in VBScript nicht unterstützt wird. Oft sind aber die Klassen- bzw. Schnittstellennamen in einem Kommentar angegeben, um Ihnen die Entwicklung in VB 6.0/VBA/VB.NET zu erleichtern.
4.5.3
Was bedeutet die Methode say(), die in einigen Listings steht?
Die Listings in diesem Buch sind weitestgehend Scripting-Host-neutral gehalten. Als Ausgabefunktion wird die Kapselungsroutine say() verwendet. Bitte beachten Sie, dass Sie je nach Scripting Host die passende Implementierung von say() mit in das Script aufnehmen müssen, da kein Scripting Host die Prozedur von sich aus kennt. Die Implementierungen finden Sie im Kapitel zu den Scripting Hosts. Bitte bedenken Sie, dass Bildschirmausgaben in einigen Scripting Hosts gänzlich verboten sind. Sie werden aber in der Regel die hier abgedruckten Scripte auch nicht in einem komplexen Scripting Host wie dem Exchange Event Service testen wollen.
4.5.4 Kommentare
34
Was bedeuten die unterschiedlichen Kommentararten?
Für die Kommentarzeilen habe ich eine bestimmte Notation entwickelt, die in der folgenden Tabelle dokumentiert ist.
Fragen zu den Programmcodebeispielen
Kommentarzeichen
Bedeutung
' ===
Kommentar zu einem eigenständigen Script
' ###
Kommentar zu einer Hilfsroutine, die von einem eigenständigen Script oder einer anderen Hilfsroutine aufgerufen wird
' %%%
Beginn einer Liste von Konstantendefinitionen
' ---
Zentraler Kommentar innerhalb einer Routine
'
Sonstige Kommentare innerhalb einer Routine
4.5.5
Tabelle 4.2: Kommentarzeichen
Was bedeutet die Kommentare, in denen „as“ vorkommt?
Das Schlüsselwort „as“ wird in Visual Basic 6.0, VBA und VB.NET verwendet, um eine Variable zu typisieren. VBScript erlaubt diese Typisierung nicht. Es ist jedoch sinnvoll, den Typ als Kommentar anzugeben, um die erwarteten Informationen zu dokumentieren und um leichter Hilfe in der Dokumentation zu finden.
4.5.6
Welche Infrastruktur haben Sie für dieses Buch verwendet?
Viele administrative Scripte benötigen Informationen über Ihr Arbeitsumfeld wie zum Bei- Aufbau der spiel Servernamen und Anmeldeinformationen. Die Scripte in diesem Buch bzw. auf der Testumgebung CD-ROM zu diesem Buch enthalten die konkreten Namen für eine Rechnerinfrastruktur, in der diese Scripte entwickelt und getestet wurden. Für den Test der Scripte haben Sie zwei Möglichkeiten: 왘 Nachbau der Testumgebung oder 왘 Anpassung der Umgebungsinformationen in den Scripten
Die Anpassung der Scripte ist problemlos. Die folgende Beschreibung der Testumgebung hilft Ihnen, zu erkennen, welche Angaben in den Scripten Schlüsselwörter sind und welche Eigennamen sind, die Sie ersetzen müssen. Wenn Sie aber sowieso gerade dabei sind, eine Testumgebung aufzubauen, erwägen Sie doch den Nachbau dieser Umgebung. Die Testumgebung dreht sich um die beliebte Fernsehserie „Akte X“ (engl. X-Files). Die Active Directory-Domäne heißt „FBI.net“ mit dem NETBIOS-Namen „FBI“. Die beiden Domänen-Controller heißen „XFilesServer01“ und „XFilesServer02“. In der vierten Auflagen waren die Domänen-Controller Windows Server 2003. In der fünften Auflage sind Sie mit Windows Server 2003 Release 2 neu aufgesetzt worden. Die Namen der Clients haben die Form „EXX“, wobei die beiden X für jeweils eine Ziffer stehen (z.B. „E51“). Als Organisationseinheiten und Benutzer existieren bzw. werden im Rahmen dieses Kapitels angelegt: 왘 Organisationseinheit „Agents“ mit Benutzern wie „Fox Mulder“, „Dana Scully“, „John
Doggett“ und „Monica Reyes“ 왘 Organisationseinheit „Directors“ mit Benutzern wie „Walter Skinner“ und „Alvin
Kersh“
35
4 Fragen und Antworten zu diesem Buch (FAQ)
왘 Organisationseinheit „Conspirators“ mit „Smoking Man“ und „Deep Throat“ 왘 Organisationseinheit „Aliens“ mit zahlreichen Außerirdischen 왘 Im Benutzercontainer gibt es außerdem den Benutzer „HS“.
Bild 4.7: Ein Blick in das Verzeichnis FBI.net
Auf dem XFilesServer01 ist ein Microsoft Exchange Server 2003 installiert. Auf dem XFilesServer02 existiert jeweils eine Instanz von Microsoft SQL Server 2000 und 2005. Zwischen den Auflagen hat sich die Testumgebung verändert. Sie finden in diesem Buch sowohl Beispiele mit der alten als auch der neuen Testumgebung. Es ist möglich, dass Sie in Programmcode und Bildschirmabbildungen auch noch Computernamen finden, die in Vorauflagen verwendet wurden. Dies sind insbesondere die Computernamen „Sonne“, „Sonne2000“, „Saturn“, „Mars“, „Erde“, „Narn“, „Minbar“ und „Zentrum“ sowie die Domänennamen „Sonnensystem“ und „IT-Visions“. Aus wirtschaftlichen Gründen ist es leider nicht möglich, die Funktionen und Codebeispiele auf „allen“ Plattformen und Systemkonfigurationen zu testen. Die folgende Tabelle nennt die drei Testplattformen, die in der fünften Auflage zum Einsatz kamen. Viele Scripte, die aus älteren Auflagen stammen, wurden in der Vergangenheit mit älteren Betriebssystemen (Windows NT 4.0, Windows 9x/ME, Windows 2000) erprobt. Durch inzwischen erschienene Ergänzungen und die Schwachstellenbeseitigungen ist es möglich, dass die Scripte nunmehr dort nicht mehr lauffähig sind.
36
Fragen zu den Programmcodebeispielen
Testplattform #1
Testplattform #2
Testplattform #3
Testplattform #4
Testplattform #5
Namen der Computer
XFilesServer01
XFilesServer02
E45
E51
E52
Betriebssystem
Windows Server 2003
Windows Server 2003 Release 2
Windows XP
Windows Vista Business
Windows Vista Business
Weitere Server
Exchange Server 2003 Internet Information Server 6.0
Microsoft SQL Internet Information Internet Server 2000 Server 5.1 Information Microsoft SQL Server 7.0 Server 2005 Internet Information Server 6.0
Internet Information Server 7.0
Service Pack SP 1
SP 1
SP 2
–
–
Domänenmitglied
Ja
Ja
Ja
Ja
1.0
1.0
1.0
1.0
Ja
PowerShell- 1.0 Version Editoren
4.5.7
SystemScripter 6.0 PowerShell IDE 1.0 PrimalScript 4.1 Beta Visual Studio 98
SystemScripter 6.0 PowerShell IDE 1.0 PrimalScript 4.1 Beta Visual Studio 98
Wie kann ich feststellen, welche ScriptingKomponenten auf meinem System installiert sind?
Die Informationen über die installierten Scripting-Komponenten stehen in der Registrierungsdatenbank. Sie werden in diesem Buch sowohl lernen, wie man diese Information direkt aus der Registrierungsdatenbank entnimmt, als auch Werkzeuge wie den COMExplorer kennen lernen, die diese Informationen einfacher auslesen. Außerdem enthält die Buch-CD-ROM ein Script, das prüft, ob die wichtigsten Komponenten auf Ihrem System vorhanden sind. Das Script befindet sich im Verzeichnis /Code_VBScript/Allgemein/Komponententest.wsf.
37
4 Fragen und Antworten zu diesem Buch (FAQ)
Bild 4.8: Ergebnis des Komponententests für eine „jungfräuliche“ Installation von Windows Vista Business
Bild 4.9: Ergebnis des Komponententests für mit Exchange Server und SQL Server ausgestatteten Windows Server 2003 Release 2
4.5.8 KomponentenSchnellinfo
38
Woher bekomme ich die notwendigen ScriptingKomponenten?
In diesem Buch finden Sie zu jeder besprochenen Komponente eine „Schnellinfo“. Diese gibt Ihnen die wichtigsten Informationen zur jeweiligen Komponente auf einen Blick. Unter anderem finden Sie dort den Hinweis auf die Verfügbarkeit und gegebenenfalls notwendige Installation der Komponenten. Oftmals ist das Problem nur, die Komponente auf dem lokalen System aufzufinden. Auch hierbei hilft die Schnellinfo, denn sie nennt die verschiedenen Namen, die eine Komponente besitzen kann.
Fragen zu den Programmcodebeispielen
Name und Abkürzung
Hier stehen der Name und die Abkürzung, mit dem bzw. der die Komponente üblicherweise in der Dokumentation und in Fachkreisen bezeichnet wird.
Name der Komponentendatei
Name der DLL oder EXE, die die Komponente implementiert. Sofern die Typbibliothek nicht Teil der Komponente ist, steht ihr Name in Klammern dahinter.
Interner Name der Typbibliothek
Hier steht der Name der Typbibliothek, wie Sie ihn im Microsoft-Objektkatalog finden und wie Sie ihn auch zur Instanziierung in der Visual Basic-IDE verwenden.
Helpstring der Typbibliothek
Hier steht der ausführliche Name der Typbibliothek (der in der IDL als „Helpstring“ angegeben wird). Dies ist der Name, der in den „Verweise“-Dialogen der Entwicklungsumgebungen erscheint.
Abweichender Programmatic Identifier (ProgID)
(Optionale Angaben) Normalerweise setzt sich die ProgID aus dem Namen, der als interner Name der Typbibliothek verwendet wird, und dem Klassennamen der jeweiligen instanziierbaren Klasse zusammen. Nur wenn die ProgIDs der (Stamm-)Klassen nicht dem in der Typbibliothek verwendeten Komponenten- bzw. Klassennamen entsprechen, nennt Ihnen dieser Eintrag die abweichenden ProgIDs.
Hersteller
Name des Herstellers
Lizenzierung
z.B. Freeware, Shareware, kostenloses Add-on, kommerzielle Komponente
Besprochene Version
Diese Information sagt Ihnen, welche Version der Komponente in diesem Buch besprochen wird.
Windows 9x/ME/NT/ 2000/XP/2003/Vista
Installationshinweise für die jeweilige Windows-Version
Dokumentation
Hier finden Sie den wichtigen Hinweis auf die Dokumentation der Komponente. Bei Microsoft-Komponenten finden Sie in der Regel einen Verweis auf die Microsoft Developer Network (MSDN) Library. Dabei wird einerseits der Weg im MSDN-Inhaltsverzeichnis angegeben und andererseits der URL für die CD-ROM-Fassung der MSDN Library in der Form [MSDN:dateiname.chm::/pfad/datei.htm]. (siehe auch Erläuterungen im Literaturverzeichnis)
Tabelle 4.3: Aufbau einer KomponentenSchnellinfo
Sofern die Komponente auf der Buch-CD-ROM enthalten ist, finden Sie einen entsprechenden Verweis bei den Installationshinweisen.
39
4 Fragen und Antworten zu diesem Buch (FAQ)
Bild 4.10: Entsprechung zwischen der KomponentenSchnellinfo in diesem Buch und der Anzeige im MicrosoftObjektkatalog (VB 6.0)
4.5.9
Was muss ich tun, wenn die Fehlermeldung „Projekt oder Bibliothek nicht gefunden“ erscheint?
Wenn beim Start einer Routine in der Visual Basic 6.0-Entwicklungsumgebung der Fehler Projekt oder Bibliothek nicht gefunden auftritt, dann liegt dies daran, dass nicht alle in das Projekt eingebundenen Komponenten auf Ihrem System registriert sind. Diese Fehlermeldung heißt allerdings nicht, dass eine für das konkrete Script notwendige Komponente fehlt: Es kann auch sein, dass irgendeine der eingebundenen Komponenten fehlt. Die Lösung: Deaktivieren Sie in diesem Fall unter PROJEKT/VERWEISE den Verweis auf die nicht vorhandenen Komponenten. Diese sind mit „NICHT VORHANDEN:“ eindeutig gekennzeichnet.
Bild 4.11: Fehlermeldung in der VB 6.0-Entwicklungsumgebung, wenn irgendeine eingebundene COM-Komponente fehlt
Bild 4.12: Anzeige der fehlenden COM-Komponenten im Verweise-Dialog
40
Fragen zur Qualitätssicherung
4.6
Fragen zur Qualitätssicherung
4.6.1
Gibt es eine Qualitätssicherung für die Inhalte in diesem Buch?
Ja. Informationen zu Verfahren und Funktionen werden grundsätzlich nicht übernommen, ohne dass sie durch mich ausprobiert wurden. Codebeispiele werden selbst erstellt und getestet. Zitierte Aussagen, die nicht mit vertretbarem Aufwand verifiziert werden konnten, werden als solche gekennzeichnet („Microsoft sagt …“ etc.). Code wird grundsätzlich in einem geeigneten Editor erstellt, kompiliert und ausgeführt. Erst dann wird der Code per Kopieren/Einfügen in das Manuskript (ein Word-Dokument) übernommen, aus dem das Buch entsteht. Die Eingabe von Code direkt in das Word-Dokument kommt nur bei einzelnen Bezeichnernamen (z.B. Klassennamen) vor. So ist sichergestellt, dass der im Buch abgedruckte Code übersetzbar ist.
4.6.2
Wie kann es sein, dass trotz der Qualitätssicherungsmaßnahmen Programmbeispiele aus Ihrem Buch auf meinem Rechner nicht funktionieren?
Trotz der Qualitätssicherung hat es immer wieder Fälle gegeben und wird es wohl auch immer Fälle geben, in denen vorher getesteter Code auf dem Zielsystem nicht läuft (Fehler erzeugt oder nicht das gewünschte Verhalten zeigt). Dies gilt nicht nur für EDV-Bücher, sondern auch für echte Anwendungen in der Praxis. Diese technischen Schwierigkeiten können verschiedene Ursachen haben: 1. Die Ursache liegt in der Systemkonfiguration (z.B. nicht vorhandene Softwarekomponenten, Rechtebeschränkungen). 2. Das Beispiel benötigt systemspezifische Angaben (z.B. Pfade, Computernamen, Domänennamen), die nicht auf die Zielumgebung angepasst wurden. 3. Sie verwenden eine Betriebssystemversion/-variante, die die Funktionalität nicht unterstützt. (Aus wirtschaftlichen Gründen können leider nicht alle Beispiele auf allen Plattformen gestestet werden.) 4. Sie verwenden eine andere Version einer Software, die eine (leicht) andere Funktionalität besitzt. 5. Auf Ihrem System sind andere Anwendungen vorhanden, die die Funktionalität beeinflussen (Seiteneffekte). Außerdem ist es grundsätzlich natürlich möglich, dass Autor, Fachlektor und Testleser etwas übersehen.
41
4 Fragen und Antworten zu diesem Buch (FAQ)
4.7
Fragen zur Unterstützung nach dem Kauf
4.7.1
Gibt es Unterstützung nach dem Kauf eines Buchs?
Hier ist grundsätzlich zu unterscheiden zwischen der technischen Unterstützung des Verlags und der inhaltlichen Unterstützung. Der Verlag bietet Ihnen Hilfe bei Fragen zur Handhabung des Buchs (z.B. bei Fehlern auf der mitgelieferten CD-ROM). http://www.Addison-Wesley.de Für inhaltliche Fragen stelle ich als Autor eine Website http://www.IT-Visions.de/Leser und Diskussionsforen http://www.IT-Visions.de/Foren bereit. Weitergehende Informationen finden Sie auch auf meiner Community-Website http://www.Windows-Scripting.de Bitte beachten Sie zwei Dinge: 1. Der Betrieb dieser Websites ist eine völlig freiwillige Leistung, für die keine Rechtspflicht besteht und die ich auch in keinster Weise entlohnt bekomme. Bitte sehen Sie es mir nach, falls es mal etwas länger dauert. 2. Ich halte es für fairer gegenüber anderen Lesern, wenn Sie Ihre Fragen in den öffentlichen Foren stellen. Bitte nutzen Sie den direkten Kontakt nur, wenn Sie Fragen haben, die nicht an die Öffentlichkeit dringen dürfen. Ich biete auch einen kommerziellen Support an, wenn Sie eine zeitnahe Antwort benötigen: http://www.IT-Visions.de/Support
4.7.2
Antworten Sie auf E-Mails, in denen ein Leser eine inhaltliche Frage stellt?
Ja. Aber ich antworte mit einer Standardnachricht, die besagt, dass man die Frage bitte in meinem öffentlichen Webforum http://www.IT-Visions.de/Foren stellen möge, wenn es möglich ist. Dort beantworte ich gerne inhaltliche Fragen. Der Grund meiner Abneigung gegen E-Mails als Medium für inhaltliche Fragen liegt in der Fairness, die ich von den Fragestellern gegenüber anderen Lesern erwarte. Wer eine Antwort möchte, sollte dazu bereit sein, dass andere auch einen Nutzen von der Antwort haben können. Dieses Fairnessprinzip wende ich auch bei meinen Hochschulstudenten an, was im Allgemeinen akzeptiert wird.
42
Fragen zur Unterstützung nach dem Kauf
Leider kann ich – auch wenn Sie das Forum verwenden – nicht garantieren, dass ich alle Fragen beantworten kann. Damit ich auch noch Zeit für andere Tätigkeiten habe (Projekte, Schulungen und Bücher), kann ich nur einen begrenzten Zeitraum pro Woche für das Forum verwenden. In manchen Wochen bin ich aufgrund von Geschäftsreisen leider gar nicht in der Lage, das Forum zu betrachten (wenn Sie mich über ein Projekt gebucht haben, würden Sie auch nicht wollen, dass ich zwischendurch anderen Leuten innerhalb Ihres Zeitbudgets helfe).
4.7.3
Wenn ich einen Fehler in dem Buch finde, möchten Sie dann, dass ich Sie darauf hinweise?
Ja, bitte. Unbedingt! Auf meiner Leser-Website http://www.IT-Visions.de/Leser gibt es dazu ein Formular, das in strukturierter Form Daten abfragt. Bitte wählen Sie diesen Weg, da es mir dann einfacher fällt, die Informationen zu katalogisieren und weiterzuverarbeiten.
4.7.4
Bieten Sie auch kommerzielle Unterstützung für Scripting, .NET und PowerShell?
Ja, das ist eigentlich mein Beruf (die Tätigkeit als Buchautor ist eher ein Hobby!). Ich biete Beratung, individuelle Schulungen, Workshops sowie die Entwicklung von Prototypen und Lösungen an. Außerdem biete ich individuelle Unterstützung bei technischen Fragen und Problemen. http://www.IT-Visions.de/Produkte
43
5
Einführung
5.1
Der Automatisierungsbedarf
Microsoft spielt auf dem Weltmarkt der Betriebssysteme eine zentrale Rolle, sowohl im GUIs Unternehmenseinsatz als auch im Heimbereich, sowohl auf dem Client als auch dem Server. Ein Grund für den Siegeszug von Windows sind die grafischen Benutzeroberflächen (engl. Graphical User Interfaces, kurz GUIs), die eine sehr einfache Bedienung ermöglichen. Fast alle administrativen Funktionen des Windows-Betriebssystems lassen sich durch ein GUI verwalten. Die Windows-GUIs zeichnen sich durch eine hohe Konsistenz aus, d.h., sie sind nach dem gleichen Prinzip aufgebaut: Sie haben alle ähnliche Menüs, Symbolleisten und Dialogfenster. Die Installation und Konfiguration eines Windows-Systems ist daher vergleichsweise einfach und intuitiv. Sofern grundsätzliche Erfahrung in der Administration eines WindowsSystems vorhanden ist, fällt die Einarbeitung in neue Aufgaben leicht. Auch Personen, die nur selten administrative Aufgaben ausführen müssen, können diese schnell erledigen, ohne komplexe Befehle beherrschen zu müssen. Ein gutes GUI ist aber nur ein Aspekt der Systemadministration. Auf der anderen Seite der Automatisierungsbedarf Medaille stehen Aufgaben, die sich nicht oder nur schlecht durch ein GUI lösen lassen: 왘 Zum einen sind dies Aufgaben, die unbeaufsichtigt, d.h. ohne Beisein eines Menschen,
왘 왘 왘
왘
von der Maschine automatisch ausgeführt werden sollen (z.B. Überwachungsaufgaben, Systemstart-Scripts sowie rechenintensive Prozesse, die nur nachts durchgeführt werden können). Zweitens sind dies wiederkehrende Administrationsaufgaben, die in definierten Intervallen ausgeführt werden sollen (z.B. Backup, Datenabgleich, Login-Scripts). In die dritte Gruppe gehören Administrationsaufgaben, die zu einem bestimmten Zeitpunkt in großer Menge anfallen (z.B. Benutzereinrichtung bei einer Systemumstellung). Viertens will ein Administrator auch bestimmte Aufgaben an andere Personen delegieren. Diesen Personen möchte er eine Routine zur Verfügung stellen, die abseits der vielfältigen Möglichkeiten eines GUI in einem fest vorgeschriebenen Dialogpfad eine bestimmte isolierte Aufgabe erledigt. Schließlich wird es immer wichtiger, Anpassbarkeit und Erweiterbarkeit in Betriebssysteme und Anwendungen zu integrieren, da es immer komplexere und individuellere Wünsche der Anwender und Administratoren gibt, die man als Softwareanbieter nicht alle in die Softwareprodukte integrieren kann.
45
5 Einführung
CLI
Derartige Aufgaben wollen Systemadministratoren üblicherweise durch ein Command Line Interface (CLI) ausführen bzw. dort automatisiert ablaufen lassen. Während unter Linux das GUI mehr als ein Add-on für das CLI zu verstehen ist, stand bei Windows immer das GUI im Mittelpunkt. Es existieren verschiedene Kommandozeilenwerkzeuge, die im Folgenden kurz besprochen werden.
5.2 Scripting und Scriptsprachen
Was ist Scripting?
Scripting ist das Schreiben eines Programms mit Hilfe einer Scriptsprache; das Programm wird in diesem Zusammenhang Script genannt. Diese Definition führt zu der Frage, was eine Scriptsprache ist. Die Antwort darauf ist jedoch nicht einfach. [FIS99] nennt folgende Kriterien zur Unterscheidung einer Scriptsprache von anderen Sprachen: 왘 Die Sprache wird interpretiert (keine Kompilierung notwendig). 왘 Scripts werden normalerweise im Quellcode gespeichert und weitergegeben. 왘 Scriptsprachen haben in der Regel einen geringen Sprachumfang. Viele typische Funk-
tionalitäten sind in externe Bibliotheken und Komponenten ausgelagert. 왘 Die Syntax ist einfach zu verwenden und zu erlernen. 왘 Es gibt nur ein sehr schwaches Typsystem. 왘 Die Abstraktion von technischen Details wie z.B. Zeigern und Speicherverwaltung ist
hoch. 왘 Eine Scriptsprache ist der Maschinensprache und der Computer-Hardware ferner als
eine normale Programmiersprache und kann daher einen Computer nicht so leicht zum Absturz bringen. 왘 Die Sprache dient dem Ad-hoc-Gebrauch. Beispiele für Scriptsprachen sind REXX, Perl, Python, AppleScript, PHP, JavaScript/JScript und VBScript. Gemäß obiger Definition sind auch die Unix-Shellsprachen wie sh und csh als Scriptsprachen zu betrachten. ALP
Zur Betonung der Anwendungsnähe und Abstraktion von technischen Details wird Scripting häufig als Application Level Programming (ALP) bezeichnet
Glue Code Scriptsprachen kommt in Zusammenhang mit komponentenorientierter Softwareentwickfür Kompo- lung oft die Rolle zu, als Verbindung (so genannter Glue Code) zwischen Komponenten zu nenten
fungieren. Diese Rolle nehmen die Scriptsprachen auch beim Active Scripting ein.
Oftmals sprechen Fachleute auch von Scripting, wenn keine Scriptsprache im engeren (oben definierten) Sinne eingesetzt wird. Dann wird Scripting mit Automatisierung gleichgesetzt, selbst wenn zur Implementierung der Automatisierungslösung eine Sprache eingesetzt wird, die keine Scriptsprache ist. Automati- Eine Anwendung wird automatisierbar (synonym: fernsteuerbar, programmierbar oder scripsierbarkeit table) genannt, wenn es möglich ist, die Anwendung durch Programmcode zu steuern.
46
Automatisierungslösungen auf der Windows-Plattform
Scriptsprache versus Batchsprache versus Makrosprache Die Begriffe Scriptsprache und Batchsprache werden leider nicht einheitlich verwendet und oft vermischt. In diesem Buch wird die Grenze zwischen Scripting und Batch hinsichtlich der Ausdrucksfähigkeit der Programmiersprache bezogen. Eine Scriptsprache ist eine vollständige Programmiersprache, die verschiedene Vereinfachungen gegenüber „echten“ Programmiersprachen für die Softwareentwicklung besitzt. Eine Batchsprache hingegen ist eine Aneinanderreihung von eigenständigen Befehlen. Dabei fehlen oft typische Programmierkonstrukte wie Bedingungen, Schleifen und Variablen. Makrosprachen sind Scriptsprachen, die innerhalb von Anwendungen zur Automatisierung der jeweiligen Anwendung dienen.
5.3
Automatisierungslösungen auf der Windows-Plattform
Das lange vernachlässigte Thema der kommandozeilenbasierten Systemadministration hat Microsoft Mitte der 90er Jahre stärker in den Fokus genommen. Microsoft bietet folgende Lösungsansätze für die automatisierte Systemadministration durch Scripting an (Stand September 2006): 왘 DOS-Batchsprache (nur im erweiterten Sinne als Scriptsprache zu bezeichnen, vgl.
Erläuterung im vorherigen Kapitel) 왘 Active Scripting-Architektur, insbesondere der Windows Script Host (WSH) 왘 Scripting mit .NET Framework-basierten Programmiersprachen wie C# und Visual
Basic .NET 왘 Microsoft Powershell
Evolutionsstufen der Windows-Programmierung © www.IT-Visions.de 2006
PowerShell Language PowerShell .NET Framework (Managed Libraries) VBScript, JScript Perl, u.a. Active Scripting
C++, J++, Visual Basic, Delphi, u.a.
Component Object Model (COM)
DOS-Befehle
C#, J#, C++/CLI, Visual Basic .NET, Delphi .NET, Fortran .NET, IronPython, u.a.
Bild 5.1: Entwicklungstufen der Programmierschnittstellen in Windows
DOS-Shell C, C++
Klassische DLLs / Windows 32-API
1993
1997
2002
2006
47
5 Einführung
Da Microsoft die Schwächen der Automatisierung mit Hilfe der DOS-Batchsprache lange Zeit nicht erkannt hat, haben sich eine Reihe anderer Ansätze entwickelt. Zu nennen sind hier insbesondere: 왘 KiXtart [KIX04] 왘 Perl for Win32 [ACT00] 왘 REXX [IBM01] 왘 AutoIt [AUT04] 왘 WinBatch [WINB04] 왘 WinRobots [WINR04] 왘 GnuWin32 (Portierung von Unix-Werkzeugen auf Windows) [GNUW04] und 왘 Bash-Shell im Rahmen von Cygwin, einer Linux-ähnlichen Umgebung für Windows
[CYG04]. In diesem Buch werden Sie das von Microsoft entwickelte Active Scripting, das .NET Framework und die Microsoft Shell (MSH) als Alternative kennen lernen.
5.4 DOS-Batch
Die DOS-Batchsprache
Die Microsoft DOS-Batchsprache, die in Einzelbefehlen im Befehlszeilenfenster oder in Form von .bat-Dateien ausgeführt werden kann, gibt es seit den Anfängen von MS-DOS. Sie war damals – zu einer Zeit, als es noch keine grafische Benutzeroberfläche namens Windows gab – ein adäquates Instrument zur Systemadministration. Sie ist auch heute noch in allen Windows-Versionen integriert, in Form des Kommandozeilenfensters (alias DOSFenster oder DOS Command Prompt). Die DOS-Batchsprache hat in all diesen Jahren allerdings nur wenige Veränderungen erfahren, obwohl die Anforderungen stets gestiegen sind. Windows war daher in diesem Bereich gegenüber Unix lange Zeit im Nachteil. In Unix gibt es mächtige Shells (z.B. bash, BourneShell, Korn-Shell, C-Shell, tcsh), in denen so genannte Shell-Scripts ausgeführt werden können, mit denen sich alle administrativen Aufgaben durchführen lassen.
Schwachpunkte
Die wesentlichen Schwachpunkte der DOS-Batchprogrammierung sind: 왘 Die DOS-Batchsprache ist keine vollständige Programmiersprache. Daher sind viele
Aufgaben nur umständlich zu bewältigen. 왘 Die Kommunikation zwischen Befehlen ist textorientiert. 왘 Ein- und Ausgabe sind zeilenorientiert. 왘 Es gibt keine Möglichkeit, Programmierschnittstellen (Application Programming Inter-
faces – APIs) des Betriebssystems oder von Anwendungen (weder komponentenbasierte noch nichtkomponentenbasierte) anzusprechen. 왘 Die Sprache ist nur über neue .cmd- oder .exe-Dateien erweiterbar. 왘 Die DOS-Befehle decken zwar die Anforderungen der DOS-Ebene ab, auf viele GUIFunktionen des Windows-Betriebssystems gibt es jedoch keinen Zugriff. Die mangelnden Fähigkeiten der DOS-Batchsprache hat Microsoft immer wieder durch neue Kommandozeilenwerkzeuge auszugleichen versucht. Insbesondere ist hier die Werk-
48
Die Active Scripting-Architektur
zeugsammlung zu nennen, die Microsoft unter dem Namen Support Tool oder Resource Kit zu den verschiedenen Betriebssystemen ausgeliefert hat. Microsoft macht kein Geheimnis daraus, dass man im Zuge der Entwicklung des Windows Server 2003 einigen Unix-Administratoren über die Schulter geschaut hat, um Ideen für die Verbesserung der befehlsbasierten Administration zu sammeln. Die Erkenntnisse aus dieser Studie manifestieren sich in einer Vielzahl neuer Kommandozeilenwerkzeuge im Windows Server 2003. Die langfristige Erkenntnis dieser Studie zeigt sich jedoch in der neuen Microsoft Shell (siehe Kapitel 10). Eine gute Darstellung der Anwendung der DOS-Sprache ist das nachfolgend empfohlene Buch. Buchtipp Armin Hanisch: Windows 2003 Shell Scripting Abläufe automatisieren ohne Programmierkenntnisse Addison-Wesley 2006, ISBN 978-3-8273-2413-9
5.5
Die Active Scripting-Architektur
Interessanterweise hat sich Microsoft des Themas Windows Scripting erst im Zuge der ActiveX Besinnung auf das Internet und der dortigen Popularität von Scriptsprachen angenommen. Scripting Seit Mitte der 90er Jahre stellen die Redmonder eine eigene modulare Scripting-Architektur für Internetanwendungen und Windows bereit. Die Windows Scripting-Architektur heißt bei Microsoft auch ActiveX Scripting, Active Scripting oder Windows Script. In diesem Buch wird vorzugsweise der Begriff Active Scripting verwendet. Grundlage der gesamten Architektur ist Microsofts Komponentenarchitektur – das Component Object Model (COM). Das Component Object Model ist Microsofts Technologie für die Entwicklung und Nutzung von objektorientierten Softwarekomponenten (zum Begriff Softwarekomponente siehe Anhang A), die COM-Komponenten genannt werden. ActiveX ist ein Marketingbegriff für einen Teil dieser Komponentenarchitektur. COM wird ausführlich in Kapitel 7 vorgestellt. COM ist objektbasiert. Daher dreht sich auch beim Active Scripting alles um Objekte und Klassen. Die Active Scripting-Architektur besteht aus folgenden drei Bausteinen: 왘 Active Scripting Hosts sind die Ablaufumgebungen für Scripts. 왘 Active Scripting Engines stellen einen Sprachinterpreter für eine bestimmte Scriptsprache
bereit. 왘 Automationsfähige COM-Komponenten ermöglichen den Zugriff auf Systemkomponenten oder stellen bestimmte Funktionalitäten in gekapselter Form bereit.
49
5 Einführung
Active Script Ein Script, das innerhalb der Active Scripting-Architektur ausgeführt wird, heißt Active Script. Bild 5.2: Die Active ScriptingArchitektur von Microsoft
Active Scripting Host (Allgemeine Darstellung)
Active Scripting Engine 1
Beispiel: Windows Script Host (WSH)
Active Scripting Engine 2
VBScriptEngine
wird ausgeführt von
wird ausgeführt von
Active Script mit Befehlen
Skriptname.vbs
greift zu auf
greift zu auf
Objekt "Instanz #1 von Klasse 1"
Objekt "Instanz #2 von Klasse 1"
liefert Instanzen
Klasse 1
Klasse 2
COM-Komponente
Objekt "c:\ Test.txt"
Objekt "d:\ Daten"
liefert Instanzen
Klasse "File"
Klasse "Folder"
Komponente "SCRRUN"
Objekt "HS"
Objekt "Adminis trator"
liefert Instanzen
Klasse "User"
Klasse "Group"
Komponente "ADSI" (C) Holger Schwichtenberg 2003-2004
Plug&Play
Die Active Scripting-Architektur ist so konzipiert, dass die einzelnen Bausteine untereinander austauschbar sind: Jeder Scripting Host kann jede Scripting Engine verwenden. Jede automationsfähige COM-Komponente kann von jedem Scripting Host und jeder Scriptsprache benutzt werden. Dies wird über wohldefinierte Schnittstellen sichergestellt. Damit ist Plug&Play zwischen Hosts und Engines verschiedener Hersteller möglich. Die Scriptsprache kann auch innerhalb eines einzigen Scripts variieren: So können etwa einzelne Unterroutinen in einer anderen Sprache als das Hauptprogramm geschrieben werden, wenn die besten Funktionen der jeweiligen Sprache genutzt werden sollen.
COM versus ActiveX
Auch Active Scripting Hosts und Active Scripting Engines sind COM-Komponenten, die spezielle Schnittstellen implementieren. Dass die Architektur ActiveX Scripting und nicht COM Scripting heißt, beruht darauf, dass Microsoft aus Marketinggründen den Begriff ActiveX gefördert hat. ActiveX wurde eine Zeit lang mit dem Begriff COM sogar völlig gleichgesetzt. In Kapitel 7 erhalten Sie eine detaillierte Einführung in COM. Host versus Sprache Die Trennung in Host und Sprache ist in vielen Scriptsprachen nicht gegeben. So steht der Begriff Personal Home Page Tools (PHP) sowohl für eine Sprache als auch für einen Scripting Host. Gleiches gilt für viele Unix-Shells.
50
Die Active Scripting-Architektur
Die Möglichkeiten der Windows-Automatisierung mit der Active Scripting-Architektur Vielfältige sind vielfältig, deshalb kommt es besonders auf die Auswahl von Scriptsprache und Kom- Möglichkeiten ponenten an, wenn es um die Frage geht, wie aufwändig ein Automatisierungsprojekt wird. Eine intensive Recherche nach vorhandenen COM-Komponenten ist ein entscheidender Erfolgsfaktor. Mit der zunehmenden Verbreitung des Komponentengedankens werden Make-or-BuyEntscheidungen zu einem ständigen Begleiter im Softwareentwicklungsprozess. Entwickler werden sich fragen lassen müssen, ob es notwendig war, eigene Routinen zu entwickeln, anstatt auf dem Markt verfügbare Komponenten zu einer Anwendung zusammenzubauen. Gerade der Active Scripting-Bereich zeigt, dass eine unterlassene Internetrecherche dazu führt, dass man sich tagelang mit Problemen beschäftigt, die andere mit wesentlich geringeren Kosten längst gelöst haben. In Kapitel 12 erhalten Sie einen Leitfaden für die Recherche nach Komponenten für das Scripting.
5.5.1
Active Scripting Hosts
Ein Active Scripting Host ist die Ablaufumgebung für ein Script und insofern vergleichbar Ablaufmit den Shells unter Unix. Der Internet Explorer war der erste Scripting Host überhaupt; mit umgebung dem Windows Scripting Host (WSH) gibt es inzwischen einen eigenständigen Scripting Host für die Windows-Plattform. Der Windows Scripting Host sollte keineswegs mit dem allgemeinen Begriff Scripting Host verwechselt werden. Er ist nur einer von vielen Active Scripting Hosts. Wohl aus Gründen der besseren namentlichen Abgrenzbarkeit nennt Microsoft diesen Scripting Host seit Version 2.0 Windows Script Host. Microsoft integriert Scripting Hosts in immer mehr Produkte, insbesondere in die Pro- Verfügbare dukte des „Windows Server System“ (früher: „.NET Enterprise Server“ und davor „Back- Scripting Hosts Office“). Aktuell sind folgende Scripting Hosts verfügbar: 왘 Active Server Pages (ASP) im Internet Information Server (IIS) (seit Version 3.0) 왘 Event Scripting Agent im Exchange Server (seit Version 5.5) 왘 Job Scripting im Server-Agent im SQL Server (seit Version 7.0) 왘 Data Transformation Scripts im SQL Server-Data Transformation Service (seit Version 7.0) 왘 Dynamic HTML-Scripting im Internet Explorer (seit Version 3.0) 왘 Outlook Forms in Microsoft Outlook (seit Version 8.0) 왘 XSL-Scripting im Microsoft XSL-Processor 왘 Installer Scripts im Windows Installer 왘 Transformationsscripts im Microsoft BizTalk Server 왘 Scriptor Component im Microsoft Commerce Server 왘 Scripts im Microsoft Operations Manager (MOM)
Scripting Hosts werden inzwischen auch von anderen Anbietern bereitgestellt. Mit dem Script Script Control bietet Microsoft zudem die Möglichkeit, auf einfache Weise einen Scripting Control Host in eigene Anwendungen zu integrieren. Zwar sind die VBA-Umgebungen (VBA steht für Visual Basic for Applications) nicht nach VBA der Windows Scripting-Architektur konstruiert, in der Praxis sind sich die Architekturen aber sehr nahe: Ein Scriptprogrammierer, der auf Visual Basic Script (VBScript) setzt, kann
51
5 Einführung
mit Cut&Paste des Quelltexts sowie mit ein paar einfachen Änderungen seine Scripts auch in VBA laufen lassen. Mit anderen Scriptsprachen geht das allerdings nicht.
5.5.2 Sprachinterpreter
Active Scripting Engines
Eine Active Scripting Engine ist ein Sprachinterpreter für eine Scriptsprache mit der Nebenbedingung, dass der Interpreter 왘 in Form einer COM-Komponente vorliegt, 왘 bestimmte Schnittstellen implementiert und 왘 für eine der entsprechenden Komponentenkategorien registriert ist.
COM-fähige Sprache versus Active Scripting-Sprache Die Anforderungen an eine Active Scripting-Sprache sind abzugrenzen von dem allgemeinen Begriff einer COM-fähigen Programmiersprache (Microsoft spricht von „COM-enabled Languages“ – ins Deutsche zum Teil mit „COM-aktivierten Sprachen“ übersetzt). Eine COM-fähige Sprache unterstützt die Nutzung von COM-Komponenten. Nicht jede COM-fähige Sprache ist auch eine Active Scripting-fähige Sprache. Beispielsweise unterstützen auch Delphi und PHP4 die Nutzung von COM-Komponenten. Dennoch sind beide Sprachen nicht im Rahmen des Active Scripting als Scriptsprachen einsetzbar. Sprachen von Verfügbare Scriptsprachen Microsoft selbst hat bislang zwei Active Scripting Engines Microsoft veröffentlicht: 왘 VBScript (eine abgespeckte Version der Programmiersprache Visual Basic) 왘 JScript (eine Erweiterung der auf Netscape JavaScript basierenden Sprachspezifikation
ECMA 262, die auch ECMAScript genannt wird) Sprachen von Es gibt weitere Scriptsprachen von anderen Anbietern (zum Großteil als Free- oder Shareanderen ware) in Form von Active Scripting Engines: Herstellern 왘 PerlScript, Active Scripting-fähige Perl-Implementierung der Firma ActiveState [ACT00] 왘 PScript, Active Scripting-fähige Perl-Implementierung der Firma MKS [MKS00] 왘 IBM unterstützt im Rahmen seiner REXX-Implementierung unter dem Namen Object
왘 왘 왘 왘 왘 왘
52
REXX Active Scripting. Object REXX ist seit Version 2.1 eine Active Scripting Engine [IBM01] [CAW01]. PythonScript, Active Scripting-fähige Version von Python [PYT00a] [PYT00b] HaskellScript, Active Scripting-fähige Version der funktionalen Scriptsprache Haskell [HAS00] ActiveScriptRuby, Active Scripting-fähige Implementierung der objektorientierten Scriptsprache Ruby [RUB01a] [RUB01b] LUAScript, Active Scripting-fähige Implementierung der in Brasilien entwickelten Sprache LUA [LUA01a] [LUA01b] TclScript ist ein Active Scripting-Wrapper für die Nutzung des Tcl-Interpreters [TCL04]. ForthScript von Mark Baker [BAK04]
Die Active Scripting-Architektur
Gerüchte um die Active Scripting-fähigen Implementierungen von Lisp und TCL konnten zum Zeitpunkt des Redaktionsschlusses dieser Auflage nicht bestätigt werden. Welche Scriptsprachen auf einem System installiert sind, erfährt man aus der Registrierungsdatenbank. Details dazu können Sie in Kapitel 7 nachlesen. Hinweise zur Auswahl der Scriptsprache in diesem Buch In diesem Buch wird durchgängig VBScript benutzt. VBScript ist die am häufigsten verwendete Sprache beim Windows Scripting. Auch auf Grund der weitgehenden Kompatibilität mit der Vollversion von Visual Basic ist VBScript die erste Wahl bei den Scriptsprachen unter Windows. Kapitel 8 stellt die Sprache ausführlich vor.
5.5.3
VBScript
COM-Komponenten
Ein Script benötigt den Zugriff auf das es umgebende System, um administrative Aufgaben Verfahren und die Interaktion mit dem Anwender durchzuführen. Grundsätzlich gibt es für eine für den Systemzugriff Scriptsprache zwei Möglichkeiten, wie sie diesen Zugriff herstellen kann: Zum einen können in der Sprache selbst Sprachkonstrukte und Funktionen integriert sein, die den Zugriff auf das System ermöglichen. Zum anderen kann die Sprache aber auch einen Mechanismus bereitstellen, um vorhandene Programmierschnittstellen (Application Programming Interfaces – APIs) anzusprechen. Die erste Möglichkeit wird von fast allen Scriptsprachen hinsichtlich rudimentärer Ein- und ZugriffsmögAusgabebefehle genutzt. Die Bereitstellung darüber hinausgehender Systemfunktionen lichkeiten auf APIs bereitet jedoch Unannehmlichkeiten. Einerseits kann die Sprache kaum plattformunabhängig sein, da jedes Betriebssystem seine eigenen spezifischen Systemfunktionen bereitstellt. Andererseits muss die Sprache ständig erweitert werden, um mit den Veränderungen der System-APIs Schritt halten zu können. Beliebter ist daher die zweite Möglichkeit (Bereitstellung eines API-Zugriffsmechanismus), die jedoch dann beschwerlich ist, wenn unterschiedliche Arten von Programmierschnittstellen unterstützt werden müssen. Microsoft geht in der ActiveX Scripting-Architektur den zweiten Weg, mit der Prämisse der Einschränkung auf eine einzige Art von Programmierschnittstellen, nämlich auf automationsfähige COM-Softwarekomponenten. Man spricht auch von Scripting-fähigen Komponenten oder einfach Scripting-Komponenten. COM steht – wie schon oben erwähnt – für „Component Object Model“. Im Kapitel zu COM werden Sie den Unterschied zwischen automationsfähigen und nicht- COM-Komautomationsfähigen COM-Komponenten genauer kennen lernen. So viel vorweg: COM- ponenten Automation ist in etwa gleichzusetzen mit einem späten Binden zur Laufzeit. Das Active Scripting mit COM ist objektbasiert („COM-Objekte“) mit instanziierbaren Klassen, die aus Methoden und Attributen bestehen. Die Klassen sind in der Regel in hierarchischen Objektmodellen angeordnet; für das Script ist die Komponente eine Objektbibliothek. Auf einen Zugriff auf Nicht-COM-APIs (z. B. DLLs, die keine COM-Komponenten sind) hat Microsoft ausdrücklich verzichtet. Es gibt jedoch inzwischen Ansätze, dies zu ermöglichen (vgl. DynaWrap). Die Arbeit mit COM-Objekten verlangt einer Programmiersprache die Unterstützung einiger grundlegender Mechanismen ab. Sofern diese jedoch implementiert sind, kann die Sprache mit einer Vielzahl unterschiedlicher COM-Objekte aus unterschiedlichen COMKomponenten zusammenarbeiten. Dies wird im Kapitel zu COM erklärt.
53
5 Einführung
Auch wenn viele COM-Komponenten COM-Automation unterstützen, gibt es dennoch Komponenten, die den Dienst nicht anbieten und daher im Windows Scripting nicht verwendbar sind. Typisierung
Komponententypen Komponenten erweitern die eingebauten Funktionen der Scriptsprachen und lassen sich aus Scripting-Sicht in zwei Typen einteilen: 왘 Einige Komponenten kapseln den Zugriff auf bestehende Programmierschnittstellen
(APIs) von Betriebssystem und Anwendungen. Die Komponenten sind hier Stellvertreter, die die (komplexen) API-Funktionen kapseln. Als positiver Nebeneffekt entsteht dabei in der Regel ein einfaches Objektmodell als Ersatz für komplexe Reihen von APIAufrufen. 왘 Andere Komponenten implementieren eigenständige Funktionalitäten, für die keine weiteren Anwendungen nötig sind. Zahlreiche Komponenten
Es sind bereits zahlreiche Komponenten für den Zugriff auf unterschiedliche Betriebssystem- und Anwendungsfunktionen verfügbar: So ermöglichen COM-Komponenten unter Windows beispielsweise den Zugriff auf 왘 Betriebssystemfunktionen wie Windows-Benutzeroberfläche, Verzeichnisdienste, Datei-
system, Registrierungsdatenbank, Eventlog, Hardware, Scheduler, MTS/COM+, Dokumente (z.B. Text, HTML, XML) und Netzwerkprotokolle (z.B. TCP, IP, HTTP, FTP), 왘 Anwendungen wie Microsoft Office, Microsoft Exchange Server, Microsoft SQL Server, Internet Information Server, aber auch auf Produkte wie Lotus Notes, Corel Draw und SAP R/3. Nicht alle Komponenten stammen von Microsoft selbst: Es gibt inzwischen unzählige Komponenten anderer Anbieter – zum Teil auch als Share- und Freeware. Auch selbst entwickelte COM-Komponenten können unabhängig von der Programmiersprache, in der sie implementiert wurden, verwendet werden. Anwendungen, die direkt komponentenbasiert entwickelt werden, lassen sich sehr einfach per Script ansteuern. Das Ende dieses Einleitungskapitel liefert einen Überblick über die wichtigsten Komponenten. WSC
Windows Script Components (WSCs) Windows Script Components (WSCs) sind in Scriptsprachen geschriebene COM-Komponenten. Der Begriff WSC steht weder allgemein für Komponenten, die von Scripts aus genutzt werden können, noch für die Bausteine der Windows Scripting-Architektur. WSCs werden in Kapitel 19 behandelt. Ausblick auf die Scripting-Komponenten in diesem Buch In den Kapiteln 10 bis 17 werden verschiedene COM-Komponenten zur Automatisierung administrativer Aufgaben in den Windows-Betriebssystemen sowie in Produkten der Microsoft Server SystemProduktfamilie (ehemals BackOffice-Server und .NET Enterprise Server) beschrieben. Die Ausführlichkeit der Darstellung in diesem Buch richtet sich vor allem nach Bedeutung und Komplexität der Komponenten. Das Active Directory Service Interface (ADSI) zur Verzeichnisdienstverwaltung und die Windows Management Instrumentation (WMI) als übergreifender Ansatz zum Systemmanagement nehmen daher den größten Raum ein. In Wichtigkeit und Umfang folgen die Scripting Runtime Library für den Dateisystemzugriff und die
54
Die Active Scripting-Architektur
WSH Runtime. Darüber hinaus werden in den oben genannten Kapiteln auch zahlreiche weitere (kleinere) Scripting-Komponenten beschrieben. Gerade bei großen Komponenten kann in diesem Buch nur ein repräsentativer Ausschnitt Ein repräsender Komponente besprochen werden. Besonderes Ziel ist es daher, Ihnen ein Grundver- tativer Ausschnitt ständnis jeder einzelnen Komponente zu geben, damit Sie sich anschließend selbst weiter orientieren können. Zur Veranschaulichung ist das Objektmodell in Form einer Grafik wiedergegeben. Hinweise zu der dort verwendeten Notation sowie zu den Listings finden Sie im Anhang. Auf eigener Suche Mit Sicherheit werden Sie nach der Lektüre dieses Kapitels noch die eine oder andere Funktionalität vermissen. Auf der Suche nach Komponenten hilft Ihnen das in Kapitel 18 vorgestellte Vorgehensmodell.
5.5.4
Werkzeugunterstützung
Die Werkzeugunterstützung der Scriptentwicklung unter Windows ist noch verbesserungswürdig. Mit Visual InterDev liefert Microsoft zwar eine Scriptentwicklungsumgebung; diese unterstützt aber bislang fast nur die Scriptprogrammierung im Web. In vielen Scripting Hosts (z.B. SQL Server Agent, Microsoft Outlook) stehen nur sehr primitive Editoren bereit, so dass die Scriptprogrammierung sehr mühsam ist.
Editoren, Debugger und andere Tools
Auch hinsichtlich des Debugging ist die Werkzeugunterstützung noch nicht optimal, wenn man die Entwicklungsumgebungen wie Visual C++ 6.0 und Visual Basic 6.0 als Maßstab nimmt. Inzwischen gibt es zum Teil bessere Lösungen von Drittanbietern. Einen Überblick über die verfügbaren Werkzeuge liefert Kapitel 18.
5.5.5
Active Scripting versus VBA
Das in Microsoft Office und vielen Anwendungen anderer Hersteller enthaltene Visual Basic for Applications (VBA) kann zum Teil als eine Konkurrenztechnologie zum Active Scripting angesehen werden. Auch VBA ist eine Interpreter-Sprache, die es ermöglicht, auf einfache Weise Anwendungen um Automatisierungsfähigkeit zu erweitern. Die Unterschiede zwischen VBA und Active Scripting aus der Sicht eines Softwareherstellers, der seine Software anpassbar und erweiterbar machen möchte, zeigt die folgende Tabelle. Visual Basic for Applications (VBA)
Active Scripting
• nur eine Programmiersprache (Visual Basic for Applications) • komfortable Entwicklungsumgebung wird von Microsoft bereitgestellt • Softwarehersteller zahlt an Microsoft
• viele Programmiersprachen (alle Active Scripting-fähigen Sprachen) • keine Entwicklungsumgebung (muss gegebenenfalls vom Softwarehersteller selbst erstellt werden) • kostenlos
55
5 Einführung
5.6 Das .NET Framework
Scripting im .NET Framework
Das Microsoft .NET Framework ist eine Programmierplattform, die Microsoft im Jahre 2002 als Nachfolgeprodukt für das Component Object Model (COM) eingeführt hat. Das .NET Framework bietet gegenüber COM viele neue Möglichkeiten, umfasst jedoch andererseits in den ersten Versionen noch nicht alle Einsatzgebiete von COM. Echtes Scripting (interpretierter Code zur Ad-hoc-Programmierung) ist im .NET Framework grundsätzlich möglich, wird aber von dem Framework bisher nur rudimentär unterstützt. Es gibt von Microsoft noch keinen „Windows Script Host .NET (WSH.NET)“, der auf dem .NET Framework aufsetzend eine Scripting-Architektur bereitstellt. Scripting im .NET Framework ist durch zwei Ansätze möglich: 왘 Der Autor dieses Buchs hat selbst einen Scripting Host auf Basis des .NET Framework
entwickelt, den DOTNET Scripting Host (DSH). Der DSH ist hinsichtlich seiner Nutzung dem COM-basierten WSH sehr ähnlich, steht aber auf einer ganz anderen technologischen Basis und bietet daher viele Vorteile. Der DSH ist Freeware; die Version 1.1 finden Sie auf der CD im Verzeichnis [CD:/install/dotnet/DSH]. Beschrieben ist der DSH in der 4. Auflage dieses Buchs. Zugunsten der Microsoft PowerShell ist dieses Kapitel in der 5. Auflage entfallen. 왘 Microsofts Ansatz zum Scripting mit dem .NET Framework ist die Microsoft PowerShell (PS), siehe nächstes Kapitel.
5.7
Die Microsoft Powershell
Das Active Scripting ist einigen Administratoren zu komplex, weil es viel Wissen über objektorientiertes Programmieren und das Component Object Models (COM). Die vielen Ausnahmen und Ungereimheiten (daher ist dieses Buch auch so dick) erschweren das Erlernen von Windows Script Host und seinen Host-Kollegen. Mit dem Erscheinen des .NET Framework im Jahre 2002 wurde lange über einen WSH.NET spekuliert. Microsoft hat die Neuentwicklung des WSH für das .NET Framework aber eingestellt, weil abzusehen war, dass die Verwendung von .NET-basierten Programmiersprachen wie C# und Visual Basic .NET dem Administrator nur noch mehr Kenntnisse über objektorientierte Softwareentwicklung abverlangen würde. Microsoft hat beobachtet, dass in der Unix-Welt eine hohe Zufriedenheit herrscht mit den dortigen Kommandozeilen-Shells. Microsoft hat sich daher entschlossen, das Konzept der Unix-Shells, insbesondere das Pipelining, mit dem .NET Framework zusammenzubringen und daraus eine .NET-basierte Windows Shell zu entwickeln, die so einfach ist wie eine Unix-Shell, aber so mächtig sein kann wie das .NET Framework. In einer ersten Beta-Version wurde die neue Shell schon unter dem Codenamen „Monad“ auf der Professional Developer Conference (PDC) im Oktober 2003 in Los Angeles vorgestellt. Nach den Zwischenstufen „Microsoft Shell (MSH)“ und „Microsoft Command Shell“ trägt die neue Scriptumgebung seit Mai 2006 den Namen „Windows PowerShell“. Derzeit aktuell ist der so genannte „Release Candidate“, der den Ausführungen in diesem Buch zu Grunde liegt.
56
Die Microsoft Powershell
Bild 5.3: Verzeichnisauflistung in der Microsoft PowerShell Version 1.0
Die PowerShell sieht auf den ersten Blick aus wie ein DOS-Kommandozeilenfenster (siehe Abbildung 5.3), nur mit blauem statt schwarzem Hintergrund. Unter der Haube bietet sie jedoch folgende Highlights: 왘 eine den Unix-Shells ähnliche Scriptsprache, 왘 wahlweise starke oder schwache Typisierung sowie eine dynamische Erweiterung von Typen, 왘 über einhundert vordefinierte Befehle, die Commandlets genannt werden, 왘 typisiertes Pipelining (Objekt-Pipelining) zwischen Commandlets, 왘 einheitliches Navigationsmodell für Datenmengen (sowohl flache als auch hierarchische
왘 왘 왘 왘
Datenmengen, z.B. Dateisystem, Registrierungsdatenbank, Active Directory, Umgebungsvariablen), Zugriff auf alle Objekte, die das .NET Framework, COM-Komponenten und die Windows Management Instrumentation (WMI) zur Verfügung stellen, eingebaute Vereinfachungen für ausgewählte Komponenten (insbesondere ADSI, WMI und System.Xml), eingebaute Sicherheitsfunktionen zum Schutz vor „bösen“ Scripts, eigene Commandlets zur Erweiterung der Fähigkeiten der Powershell können in jeder .NET-basierten Programmiersprache geschrieben werden. Bild 5.4: Objekt-Pipelining in Aktion in der PowerShell
57
5 Einführung
Bild 5.5: Navigieren in der Registrierungsdatenbank
Die PowerShell wird ausführlich im Buchteil C behandelt.
5.8
Neuerungen in Windows Vista im Überblick
Fünf Jahre nach Windows XP erscheint Anfang 2007 endlich das neue Windows-Clientbetriebssystem mit Namen „Windows Vista“, das vorher den Codenamen „Longhorn“ trug. Die folgenden Ausführungen basieren auf dem Release Candidate 1 von Windows Vista und der bis zum 7.9.2006 verfügbaren Dokumentation.
5.8.1
Scriptumgebungen
Der Windows Script Host (WSH) trägt in Vista die Versionsnummer 5.7 (gegenüber 5.6 in Windows XP und Windows Server 2003). Neue Funktionen sind aber im Release Candidate 1 weder erkennbar noch dokumentiert. Als neue Active Scripting-basierte Scriptumgebung sind die Microsoft Gadgets hinzugekommen. Gadgets sind scriptbasierte Mini-Anwendungen für Desktop und die neue Sidebar. Die Microsoft Powershell, die einmal geplant wurde als ein Teil von Windows Vista, ist weder im Installationsumfang von Vista noch auf der CD-ROM enthalten, sondern muss separat aus dem Internet heruntergeladen und installiert werden.
58
Neuerungen in Windows Vista im Überblick
5.8.2
Scriptbibliotheken
Windows Vista enthält zahlreiche neue Programmierschnittstellen. Interessanterweise sind darunter nicht nur moderne .NET-basierte Schnittstellen, sondern auch viele Schnittstellen, die auf alten Techniken wie C++ und COM basieren. Im Folgenden werden nur die Neuerungen genannt, die für das Thema dieses Buchs relevant sind. COM-basierte Schnittstellen 왘 Erweiterungen in der Windows Management Instrumentation (WMI) sowohl beim 왘 왘
왘 왘
Metaobjektmodell als auch bei den WMI-Klassen Windows Remote Management (WinRM) zum entfernten Zugriff auf WMI-Objekte über Webservices (XML/HTTP) (auch verfügbar für Windows Server 2003 Release 2) Windows RSS Platform („Microsoft Feeds, Version 1.0“) zum Zugriff auf Nachrichtenkanäle, die Really Simple Syndication (RSS) (auch für Windows XP und Windows Server 2003, wenn Internet Explorer 7.0 installiert wird) Task Scheduler 2.0 Scripting Objects zum Zugriff auf den neuen Zeitplandienst in Vista OLEDB Provider for Windows Search (MSIDXS) zur Suche im Vista-Dateisystem
.NET-basierte Schnittstellen Die .NET-basierten Schnitsttellen in Windows Vista sind im .NET Framework 3.0 zusammengefasst. Gegenüber dem .NET Framework 2.0 bietet die Version 3.0 folgende neuen Bibliotheken: 왘 Die Windows Presentation Foundation (WPF) für grafische Benutzerschnittstellen
(Codename Avalon) 왘 Die Windows Communication Foundation (WCF) für Fernaufruf und Anwendungskopplung (Codename Indigo) 왘 Mit der Windows Workflow Foundation (WF) können Entwickler eigene Anwendungen um rechnergesteuerte Arbeitsabläufe erweitern. 왘 Windows Cardspaces ist eine Bibliothek zur Verwaltung digitaler Identitäten. .NET Framework 3.0 Das .NET Framework 3.0 besteht aus der gleichen Laufzeitumgebung (Common Language Runtime – CLR) wie das .NET Framework 2.0. Auch die Syntax der Programmiersprachen ist gleich. Neu sind lediglich die zusätzlichen Bibliotheken, die optional verwendet werden können. Das .NET Framework 2.0 kann auch auf älteren Windows-Versionen als Add-on installiert werden. Allerdings lassen sich die neuen oben genannten Bibliotheken nur auf Windows XP und Windows Server 2003 installieren.
59
6
Scripting-Schnellstart
Wenn Sie noch nie ein Script unter Windows erstellt haben, werden Ihnen die folgenden vier Beispiele erste Erfolgserlebnisse bereiten. Voraussetzung für das erste Beispiel ist, dass Sie den Windows Scripting Host installiert WSH 2.0 und haben. Sie sollten in Ihrem Windows-Verzeichnis eine Datei WScript.exe finden. Wenn Sie IE ab 4.0 Windows 2000 benutzen, können Sie fast sicher sein, dass Sie den WSH 2.0 auf Ihrem System haben. Unter Windows 98 ist der WSH in der Version 1.0 eine Installationsoption; unter NT 4.0 gibt es den WSH nur als separates Add-on. Windows XP und Windows Server 2003 enthalten den WSH 5.6. Wenn der WSH 2.0 nicht vorhanden ist, installieren Sie ihn bitte von der Buch-CD aus dem Verzeichnis /install/hosts/wsh. Voraussetzung für das zweite Beispiel ist ein installierter Internet Explorer ab Version 5.0. Die beiden Scripts befinden sich natürlich auch auf der Buch-CD [CD:/code/Einfuehrung/]. Jedoch sollten Sie sich an dieser Stelle durchaus die Mühe machen, die Scriptdateien selbst zu erstellen.
6.1
Ein einfaches Script für den Windows Script Host
So erstellen Sie Ihr erstes Script für den Windows Scripting Host in der Sprache Visual Basic Ihr erstes Script Script: 왘 Legen Sie eine Textdatei an, indem Sie irgendwo auf dem Desktop oder in einem Ver-
zeichnis im Dateisystem im Kontextmenü Neu|Textdatei wählen. Es erscheint eine Datei Neue Textdatei.txt. 왘 Benennen Sie die Datei in ErstesSkript.vbs um. Bestätigen Sie die Nachfrage des Betriebssystems, ob die Dateierweiterung wirklich geändert werden soll. 왘 Wählen Sie aus dem Kontextmenü der Datei Bearbeiten, so dass sich der Notepad öffnet. (Sofern Sie einen anderen Editor installiert haben, mag jetzt dieser gestartet werden.) 왘 Geben Sie Folgendes in die erste Zeile ein: MsgBox "Ab heute kann ich skripten!" 왘 Speichern Sie die Änderungen ab. Sie können den Editor schließen, müssen es aber
nicht.
61
6 Scripting-Schnellstart
왘 Doppelklicken Sie auf die Datei ErstesSkript.vbs. Wenn Sie alles richtig gemacht haben
und das System Ihnen wohlgesonnen ist, wird die nachstehend abgebildete Dialogbox erscheinen. Bild 6.1: Ausgabe des Scripts „ErstesSkript.vbs“
6.2 Ihr zweites Script
Ein komplexeres Script mit zwei Sprachen für den Internet Explorer
Das zweite Beispiel wird Ihnen bereits zeigen, wie Sie zwei Scriptsprachen innerhalb einer Scriptdatei mischen können. Als Scripting Host wird der Internet Explorer eingesetzt. 왘 Legen Sie eine Textdatei an, indem Sie irgendwo auf dem Desktop oder in einem Ver-
zeichnis im Dateisystem im Kontextmenü Neu|Textdatei wählen. Es erscheint eine Datei Neue Textdatei.txt. 왘 Benennen Sie die Datei um in ZweitesSkript.htm. Bestätigen Sie die Nachfrage des Betriebssystems, ob die Dateierweiterung wirklich geändert werden soll. 왘 Wählen Sie aus dem Kontextmenü Öffnen mit und dort Notepad. (Wenn Sie einen HTMLQuelltexteditor auf Ihrem System haben, können Sie auch diesen nutzen.) 왘 Geben Sie die folgenden Zeilen ein: Beispiel für die Mischung von ActiveX-Sprachen // ----- Unterroutine in Jscript function jadd(a,b) { return(a+b) } ' ------ Hauptprogramm in VBScript x = 5 y = 6 Ergebnis = jadd(x,y) ' JScript zur Addition nutzen msgbox x & " + " & y & " = " & ergebnis " 왘 Speichern Sie die Änderungen ab. Sie können den Editor schließen, müssen es aber
nicht. 왘 Doppelklicken Sie auf die Datei ZweitesSkript.htm. Wenn Sie alles richtig gemacht haben
und das System korrekt arbeitet, wird der Internet Explorer mit nachstehend abgebildeter Dialogbox erscheinen.
62
Benutzer aus dem Active Directory exportieren
Bild 6.2: Ausgabe des Scripts im Internet Explorer
6.3
Benutzer aus dem Active Directory exportieren
Zur Einstimmung auf die großen Möglichkeiten im Scripting des Active Directory soll hier ein Beispiel dienen, das eine Liste aller Benutzer in einem bestimmten Active DirectoryContainer, z.B. dem Users-Container, oder einer Organisationseinheit (OU) ausgibt. Das Script umfasst die folgenden Schritte: 1. Festlegung des aufzulistenden Ordners in einer Konstanten zu Beginn des Scripts. In dieser Konstante müssen Sie einen gültigen Active Directory-Container Ihres eigenen Netzwerks in Form eines LDAP-Pfads eintragen. Der Pfad muss mit LDAP:// beginnen, wobei die komplette Großschreibweise des Worts LDAP zu beachten ist. 2. GetObject() holt eine Referenz auf den Verzeichniscontainer und speichert diese in der Variablen oContainer. 3. Der Befehl oContainer.Filter = Array("user") dient dazu, die folgende Ausgabe auf die Benutzerkonten zu beschränken. Sonst würden auch in dem Container enthaltene Benutzergruppen und andere Verzeichnisdienstobjekte ausgegeben. Sowohl Gruppen als auch Benutzer erhalten Sie mit oDomain.Filter = Array("user", "group"). 4. WScript.Echo gibt den Namen des aufzulistenden Containers aus. 5. For Each...Next bildet eine Schleife, in der nacheinander alle Benutzerkonten an die Variable oUser gebunden werden. 6. Innerhalb der Schleife wird zu jedem Benutzer der Verzeichnisname, der Anzeigename und der Beschreibungstext ausgegeben. Const Pfad = "LDAP://ou=Mitarbeiter,dc=it-visions,dc=de" Set oContainer = GetObject(Pfad) oContainer.Filter = Array("user") wscript.echo "Liste der Benutzer in: " & oContainer.Name For Each oUser In oContainer wscript.echo oUser.Name & ";" & _ oUser.DisplayName & ";" & _ oUser.Description Next Listing 6.1: Liste der Benutzer in einem Active Directory-Container [Benutzerliste.vbs]
63
6 Scripting-Schnellstart
Schritte
Geben Sie das Script in einem Editor ein (oder verwenden Sie das Script auf der Buch-CDROM). Vergessen Sie nicht, den Pfad in der ersten Zeile auf Ihre Umgebung anzupassen. Speichern Sie das Script unter dem Namen benutzerliste.vbs. Das Script sollte man unbedingt mit cscript.exe in der DOS-Eingabeaufforderung starten, also z.B. mit cscript.exe benutzerliste.vbs
Würde man das Script mit dem Standardhost wscript.exe starten, würde für jedes Benutzerkonto ein Dialogfenster erscheinen. Die nächste Abbildung zeigt die mögliche Ausgabe, die man auch sehr einfach in eine Textdatei umleiten kann: cscript.exe benutzerliste.vbs >Ausgabedatei.cvs Bild 6.3: Ausgabe der Liste der Benutzer im Active Directory-Container „Users“
Wenn Microsoft Excel installiert ist, lädt ein Doppelklick auf die durch Semikola getrennte Datei die Daten in Excel. Aus Microsoft Access heraus kann die Datei sehr einfach mit der Import-Funktion in eine Datenbank eingelesen werden. Das obige Script im Listing kann auch in NT 4.0-Domänen eingesetzt werden. Dann ist als Pfad aber „WinNT://domaenenname“ anzugeben. Auch hier ist die Groß-/Kleinschreibung von WinNT exakt zu beachten.
6.4
Ein PowerShell-Beispiel
Für dieses Beispiel müssen Sie zunächst einmal die Microsoft PowerShell installieren. Die PowerShell ist auf der Buch-CD-ROM enthalten (/install/powershell). Da zum Redaktionsschluss noch nicht die finale Version vorlag, sollten Sie die aktuelle Version bei Microsoft herunterladen (deren HTTP-Adresse natürlich auch noch nicht bekannt ist).
64
Ein PowerShell-Beispiel
1. Starten Sie die PowerShell. 2. Geben Sie folgenden Befehl ein: get-wmiobject Win32_useraccount | where-object {$_.passwordexpires -eq 0 } | select-object Name,Domain
3. In der Ausgabe sehen Sie dann eine Liste der Benutzerkonten, deren Kennwort nicht abläuft. Bild 6.4: Liste der Benutzerkonten, bei denen man das Kennwort nicht wechseln muss
65
Teil B Active Scripting
7
Das Component Object Model (COM)
Dieses Kapitel stellt die Aspekte von COM dar, die aus der Sicht eines Komponentennutzers Inhalt wichtig sind. Dazu gehört auch ein gewisses Maß an Theorie. Die in diesem Zuge vermittelten theoretischen Grundlagen werden Sie in den Stand versetzen, COM-Komponenten wesentlich besser verstehen und gebrauchen zu können. Außerdem werden Sie lernen, die Dokumentationen von Komponenten besser zu verstehen. Das Kapitel beginnt mit einer zunächst kurzen Erklärung grundlegender Begriffe wie Binärstan- Aufbau dard, Laufzeitumgebungen, Komponente, Klasse, Schnittstelle, Typbibliothek, GUID, Moniker etc. Auf diesen knappen Definitionen aufbauend folgt die ausführlichere Darstellung aller wichtigen Bausteine und Konzepte von COM. Das Kapitel ist eher referenzartig aufgebaut – scheuen Sie sich nicht, einem der zahlreichen Querverweise zu folgen, wenn Sie nähere Erläuterungen zu einem Begriff benötigen. Wenn Sie darüber hinaus mehr über die Interna von COM oder die Komponentenprogram- Weitere mierung mit C++ erfahren wollen, so sind das Buch des COM-Experten Don Box [BOX98], Informationen das COM+-Werk von Eddon und Eddon [EDD00] sowie das DCOM-Buch von Victor Sirotin [SIR99] zu empfehlen. Detaillierte Informationen erhalten Sie auch auf der Microsoft COM-Site [MCO00], in der MSDN Library [MSD01d] und bei der Open Group [ATX00]. Das Component Object Model (COM) hat in dem .NET Framework (NET FX) seit dem Jahr 2002 einen mächtigen Nachfolger. Allerdings basiert das Active Scripting weiterhin auf .NET und Microsoft stellt auch in Windows Vista viele Funktionen weiterhin nur in Form von COM-Komponenten zur Verfügung.
7.1
Binärstandard
COM ist ein Binärstandard für Komponenten und daher programmiersprachenunab- Binärstandard hängig. Binärstandard bedeutet, dass 왘 es einen definierten Satz von Datentypen gibt, 왘 es eine definierte Umsetzung dieser Datentypen in Byte-Folgen gibt (z.B. wie eine Zei-
chenkette im Speicher abgelegt wird), 왘 es einen festgelegten Mechanismus gibt, wie ein bestimmter Block von Programmcode lokalisiert und aufgerufen wird.
69
7 Das Component Object Model (COM)
7.2
Programmiersprachen für COM
COM ist grundsätzlich programmiersprachenunabhängig. Die Arbeit mit COM-Komponenten verlangt einer Programmiersprache die Unterstützung des COM-Binärstandards ab. Sofern diese Unterstützung implementiert ist, kann die Sprache mit einer Vielzahl unterschiedlicher COM-Objekte aus verschiedenen COM-Komponenten zusammenarbeiten. Es sind inzwischen viele Sprachen verfügbar, die COM unterstützen. Diese Sprachen werden als COM-fähige Sprachen (engl. COM-enabled languages) bezeichnet. Dabei bieten die meisten Sprachen eine Zwei-Wege-Unterstützung. Das bedeutet, dass es sowohl möglich ist, bestehende Komponenten zu nutzen als auch in dieser Sprache eigene Komponenten zu erzeugen. Verfügbare Sprachen
Die folgende Liste zeigt eine Auswahl der COM-fähigen Programmiersprachen. Bei einigen dieser Sprachen ist die COM-Fähigkeit allerdings nicht integraler Bestandteil, sondern ein Add-on, das zusätzlich installiert werden muss. 왘 Visual Basic 왘 VBScript 왘 Visual Basic for Applications 왘 Delphi 왘 Visual C++ (Microsoft C++-Variante) 왘 Visual J++ (Microsoft Java-Variante) 왘 JScript 왘 Haskell 왘 Perl 왘 REXX 왘 PHP4 왘 DialogAPL 왘 alle .NET-Sprachen (C#, VB.NET, JScript .NET, J# etc.)
Scriptsprachen Früher boten die ActiveX-Scriptsprachen wie VBScript und JScript nur eine Ein-Weg-Unterstützung für COM. Durch das Konzept der Scriptlets können aber inzwischen auch in Scriptsprachen neue COM-Komponenten geschaffen werden.
7.3 Vereinfachungen für COM
COM-Laufzeitumgebungen
COM ist ein komplexes Modell und der direkte Zugriff auf COM ist entsprechend anspruchsvoll. Als Entwickler ist eine bessere Unterstützung bei der Nutzung und Erstellung von Komponenten wünschenswert. Dies fasst Griffel in dem Satz „DCOM liefert ... kein Komponentenframework im eigentlichen Sinne“ [GRI98, Seite 84] zusammen. Daher existieren für verschiedene Programmiersprachen Laufzeitumgebungen, die den Zugriff auf die Funktionen der COM-Bibliothek und den Umgang mit einzelnen COMKomponenten ebenso wie die Implementierung neuer COM-Komponenten vereinfachen.
70
COM-Laufzeitumgebungen
Diese Laufzeitumgebungen bieten Implementierungen für verschiedene COM-Standardschnittstellen (insbesondere IUnknown und IDispatch) und ermöglichen somit die einfache Nutzung zahlreicher COM-Dienste. Die Laufzeitumgebungen der verschiedenen COM-fähigen Programmiersprachen sind nicht zu verwechseln mit der COM-Bibliothek, welche das Application Programming Interface (API) von COM verkörpert (siehe Kapitel 7.15). Leider hat bisher jede COM-fähige Sprache ihre eigene Laufzeitumgebung und daher ihre Uneinheiteigene Weise der COM-Programmierung. Eine einheitliche Laufzeitumgebung für COM- lichkeit Komponenten ist bislang nicht vorhanden. Der COM-Standard definiert nur, wie Komponenten auf binärer Ebene genutzt werden sollen; aus der Sicht des Programmierers ergeben sich jedoch je nach Sprache, in der der COM-Client implementiert werden soll, große Unterschiede in der Art des Umgangs mit den Komponenten. Die VB Runtime für Visual Basic und Active Template Library (ATL) für Visual C++ sind VB Runtime, zwei Ansätze für eine Laufzeitumgebung. Die ATL befreit den C++-Entwickler beispiels- ATL weise davon, den QueryInterface()-Mechanismus und die Referenzzählung mit AddRef() und Release() für jede COM-Klasse selbst zu implementieren. (Diese Funktionen werden in Kapitel 7.15 erläutert!) Es wäre wünschenswert, wenn COM selbst eine solche Laufzeitumgebung bereitstellen würde, damit diese Laufzeitumgebung für alle Sprachen gleich wäre. Dieses Feature war ursprünglich für COM+ angekündigt (vgl. die inzwischen berühmte Ankündigung einer COM+-Laufzeitumgebung von Mary Kirtland aus dem Microsoft Systems Journal [KIR98]), wurde jedoch nicht realisiert.
Sprachen
Laufzeitumgebungen
Klassenbibliotheken
Komponentenmodelle
© www.IT-Visions.de 2001-2006
VB6
JScript VBScript
Andere COMSprachen
VBRuntime
Active Scripting
Andere Laufzeitumgebung
C++
ATL
MFC
FSO
ADSI
ADO
CDO
COM-Komponenten
DMO
WMI
MS XML
...
Bild 7.1: Verschiedene Laufzeitumgebungen in COM
COM-API
Win32-API
71
7 Das Component Object Model (COM)
7.4 Bausteine
Bild 7.2: ER-Diagramm der Bausteine von COM (Windows 9x/ ME/2000)
COM-Bausteine
Die COM-Spezifikation definiert eine Reihe von Bausteinen (hier sollte man nicht von „Objekten“ sprechen, weil der Begriff Objekt in der objektorienierten Programmierung bereits als Bezeichnung für die Instanz einer Klasse benutzt wird – vgl. Anhang A). Diese Bausteine betreffen einerseits den Aufbau einer Komponente, andererseits auch die mit einer Komponente in Beziehung stehenden Konfigurationsdaten. Die wichtigsten COMBausteine und ihre Beziehungen zueinander sind in der folgenden Grafik in Form eines aus der Datenmodellierung bekannten Entity-Relationship-Diagramms (ER-Diagramm) dargestellt. Das ER-Diagramm zeigt auch weitere COM-spezifische Konzepte, die in diesem Kapitel noch erläutert werden (siehe folgende Abbildung). LibID (GUID)
1
hat
Typbibliothek
1
hat
1
0/1 beschrieben in
n
IID (GUID)
1
hat
1
hat
m
1
hat
Attribut
n
COMSchnittstelle
1
Methode
n
1 hat
implementiert
Ereignis
n
1
n
CLSID (GUID)
1
hat
COMKlasse
1 1
n
n
n
COMKomponente
1
bildet
1 1
1
ProgID
0/1
hat gespeichert in
Friendly Name
bildet
gehört zu
hat
hat
0/1 n
COM-Objekt (Instanz)
1
COM-Datei (exe,dll,etc.)
1
AppID (GUID)
1
hat
1
1
COM-Anwendung
1 hat
m
CatID (GUID)
1
hat
1
COM-Kategorie
0/1
Moniker
1
hat
1
MonikerObjekt (C) Holger Schwichtenberg 2001
72
COM-Bausteine
LibID (GUID)
1
hat
Typbibliothek
1
hat
1
0/1 beschrieben in
n
IID (GUID)
1
hat
1
hat
m
1
hat
Attribut
n
COMSchnittstelle
1
Methode
n
1 hat
implementiert
Ereignis
n
1
n
CLSID (GUID)
1
hat
COMKlasse
1 1
n
n
n
COMKomponente
1
bildet
Application Manifest
Assembly Manifest
1 1
1
1
1
ProgID
0/1
hat gespeichert in
Friendly Name
bildet
gehört zu
besitzt ein
besitzt ein
hat
hat
0/1 n
COM-Objekt (Instanz) 1
AppID (GUID)
1
CatID (GUID)
1
hat
1
1
n
1
1
wird verwendet von
n
Anwendung 1
1 hat
1
1
1
Assembly
umfasst
1
COM-Anwendung
m hat
1
COM-Datei (exe,dll,etc.)
besitzt ein
besitzt ein
COM-Kategorie 1
1 0/1
Moniker
1
hat
1
MonikerObjekt
hierarchischer Name
hierarchischer Name
(C) Holger Schwichtenberg 2001
Bild 7.3: ER-Diagramm der Bausteine von COM (Windows XP und Windows Server 2003)
7.4.1
Die wichtigsten Bausteine im Kurzüberblick
COM-Komponenten sind objektorientierte Komponenten in dem in Anhang A beschriebe- Komponente nen Sinne. Sie sind die binäre Form einer Menge von COM-Klassen. Nicht jede Ansammlung von Klassen im objektorientierten Sinne ist aber eine (COM-) Komponente. So kann eine Anwendung auf Klassen basieren, die mangels der Implementierung von COM-Standardschnittstellen keine COM-Klassen sind und daher auch keine COM-Komponente bilden. Eine weitere Verwirrung in der COM-Begrifflichkeit entsteht dadurch, dass zum Teil die KlassenBegriffe Klassenbibliothek, Objektbibliothek oder COM-Bibliothek synonym mit COM- bibliothek Komponente benutzt werden. Dabei ist der Begriff COM-Bibliothek natürlich besonders ungeeignet, da er in Konflikt mit der eigentlichen COM-Bibliothek steht, die Teil der Standardimplementierung von COM ist. Eine COM-Komponente fasst COM-Klassen zu einer Einheit zusammen. Eine COM-Kom- Klasse ponente enthält mindestens eine COM-Klasse; in der Regel sind es jedoch mehrere Klassen. Weitere Informationen zu COM-Klassen finden Sie in Kapitel 7.10. Wenn eine COM-Klasse instanziiert wird, entsteht ein COM-Objekt (Instanz der Klasse).
Objekt
73
7 Das Component Object Model (COM)
Schnittstelle
Eine COM-Klasse ist die Implementierung einer oder mehrerer COM-Schnittstellen, wobei jede Schnittstelle eine beliebige Anzahl von Methoden umfasst. Weitere Informationen zu COM-Schnittstellen finden Sie in Kapitel 7.11.
Typbibliothek
Eine Typbibliothek (engl. Type Library, kurz: TypeLib) enthält eine formale Beschreibung der Klassen und ihrer Schnittstellen und deren Mitglieder. Eine COM-Komponente kann eine Typbibliothek haben, sie muss aber keine haben. Typinformationen sind Thema in Kapitel 7.13.
COM-Anwen- Eine COM-Anwendung fasst eine oder mehrere COM-Klassen zusammen und ermöglicht dungen die gemeinsame Konfiguration dieser Klassen. Zahlreiche Einstellungen (z.B. Sicherheits-
einstellungen) sind nur auf Anwendungsebene, nicht jedoch für eine einzelne Klasse konfigurierbar. Jede COM-Klasse kann nur einer COM-Anwendung angehören. Alle Einstellungen einer COM-Anwendung gelten für alle zugehörigen Klassen. Mehr Informationen zu COM-Anwendungen finden Sie in Kapitel 7.18. Komponentenkategorien
COM-Kategorien stellen eine Möglichkeit dar, COM-Klassen zu kategorisieren. Die Kategorisierung dient dazu, leichter feststellen zu können, ob ein COM-Client und ein COM-Server zusammenpassen. Mehr Informationen zu COM-Komponentenkategorien finden Sie in Kapitel 7.19.
Assembly
Eine Assembly ist eine feste Ansammlung von einer oder mehreren Komponentendateien, die zum Zwecke der Versionierung zusammengefasst werden. Eine Assembly besitzt eine Konfigurationsdatei, die Assembly Manifest heißt. Ein Assembly Manifest ist eine XML-Datei. Eine Assembly soll einen hierarchischen Namen besitzen in der Form Firmenname.Anwendungsname.Anwendungsteil.Komponentenname
Das Konzept der Assemblies wurde erst mit Windows „Whistler“ (Windows XP und Windows Server 2003) eingeführt. Assemblies und Manifeste in COM sind ähnlich, aber nicht gleich den Assemblies und Manifesten im .NET Framework. Client und Server
COM-Server und COM-Client Oft wird auch der Begriff COM-Server für eine Komponente verwendet. Dieser Begriff stellt in den Vordergrund, dass eine Komponente ein Dienstanbieter ist. In Abgrenzung dazu heißt der Nutzer COM-Client. Ein COM-Client kann eine „normale“ Anwendung, ein Script oder wiederum eine Komponente sein. Die Begriffe COM-Server und COM-Client werden immer dann benutzt, wenn klar abgegrenzt werden soll, wer Dienstnutzer und wer Dienstanbieter ist. Ein COM-Client kann natürlich selbst wiederum ein COM-Server für einen anderen COM-Client sein. Aus der Sicht eines COM-Clients ist ein COM-Server lokal (d.h. auf dem gleichen Rechnersystem) oder entfernt (engl. remote, d.h. auf einem anderen physikalischen Rechner). Oft werden die Begriffe COM-Server und COM-Client auch für einzelne COM-Objekte und nicht nur für ganze COM-Komponenten verwendet.
74
COM-Bausteine
7.4.2
Global Unique Identifier (GUIDs)
Die Spezifikation von COM verlangt, dass zentrale Bausteine der Komponentenarchitektur GUIDs eindeutig identifizierbar sind. Diese Kennung soll nicht nur innerhalb eines Systems, sondern über Raum und Zeit eindeutig sein. Derartige Kennungen werden in COM Global Unique Identifier (kurz: GUIDs) genannt. Einige Autoren sprechen auch von Universal Unique Identifier (kurz: UUID). Der Nummernraum soll theoretisch ausreichen, um in der Zukunft auch über unseren eigenen Planeten hinaus Eindeutigkeit zu gewährleisten. GUIDs werden mit Hilfe eines im Distributed Computing Environment (DCE) der Open DCE-AlgoSoftware Foundation (OSF) spezifizierten Algorithmus aus dem Netzwerknamen des Com- rithmus puters und der genauen aktuellen Uhrzeit gebildet. Sofern der Computer über keinen Netzwerknamen verfügt, wird eine Zufallszahl gebildet, die höchstwahrscheinlich eindeutig ist. Die Eindeutigkeit ist wahrscheinlich auf Grund der Größe der GUIDs: Sie umfasst 16 Byte (128 Bit), also einen Bereich von rund 3,4028236e+38 Werten (2 hoch 128). Im Kontext mit einem bestimmten Baustein haben die GUIDs besondere Namen (vgl. Tabelle 7.1). Die OSF ist ein Konsortium von Soft- und Hardwareherstellern. DCE definiert eine Umgebung für verteilte Systeme mit Werkzeugen und Diensten für verteilte Anwendungen. Zentraler Dienst im DCE ist der Remote Procedure Call (RPC), der entfernte Aufruf von Unterroutinen. COM-Baustein
GUID-Name
COM-Klasse
Class Identifier (CLSID)
COM-Schnittstelle
Interface Identifier (IID) oder Interface Pointer Identifier (IPID)
COM-Typbibliothek
Library Identifier (LibID)
COM-Komponentenkategorie
Category Identifier (CatID)
COM-Anwendung
Application Identifier (AppID)
Tabelle 7.1: Verschiedene Typen von GUIDs in COM
GUIDs werden in der Regel als eine 16-stellige hexadezimale Zahl dargestellt, eingerahmt in GUIDGEN geschweifte Klammern. GUIDs können mit dem Werkzeug GUIDGEN (guidgen.exe) erzeugt werden. GUIDGEN wird u.a. mit Visual Studio 6.0 ausgeliefert. Beispiel
GUID
VBScript Scripting Engine
{B54F3741-5B07-11cf-A4B0-00AA004A55E8}
Microsoft Word 2000
{000209FF-0000-0000-C000-000000000046}
Klasse für LDAP Namespace
{228D9A82-C302-11cf-9AA4-00AA004A5691}
IUnknown-Schnittstelle
{00000000-0000-0000-C000-000000000046}
IDispatch-Schnittstelle
{00020400-0000-0000-C000-000000000046}
Tabelle 7.2: Beispiele für GUIDs in COM
Folgende Identifikatoren in Zusammenhang mit COM sind keine GUIDs: 왘 so genannte Local Identifier (LCID), die Regionen bezeichnen 왘 Dispatch-IDs (vgl. Kapitel 7.14) 왘 ProgIDs (vgl. Kapitel 7.10)
75
7 Das Component Object Model (COM)
Manchmal benötigt man in Scripts eine zufällige, aber eindeutige Bezeichnung. In diesem Fall kann man mit dem Script in dem nachfolgenden Listing einen GUID erzeugen. ' === Teste das Erzeugen eines GUID Sub GUIDTest() MsgBox CreateGUID(), , "Eine neue GUID" End Sub ' ### Hilfsfunktion: Erzeugen eines GUID Function CreateGUID() Set o = CreateObject("Scriptlet.TypeLib") tg = o.guid ' letzte zwei Zeichen abziehen CreateGUID = Left(tg, Len(tg) - 2) End Function Listing 7.1: Erzeugen eines GUID
7.4.3 Moniker
Moniker
Die Namen für Instanzen heißen in der COM-Welt Moniker (engl.: Spitzname). Moniker sind eine textliche Repräsentation der Pfadangabe zu einem Objekt. Sie sind keine GUIDs. Es ist keine Pflicht für eine Instanz, einen Moniker zu haben. Moniker haben die Form einer im Internet gebräuchlichen Uniform Resource Locator (URL). Eine URL hat die allgemeine Form Protokoll:Protokoll-spezifischer Teil
Ein Moniker hat die Form Moniker-Typ:Moniker-Typ-spezifischer Teil
Ein Moniker-Typ wird auch als Moniker-ProgID bezeichnet. Tabelle 7.3: Ausgewählte Beispiele für Moniker-Typen
76
Moniker-Typ
Erläuterung
File://
Datei oder Ordner im Dateisystem
WinNT://
Objekt im NT 4.0-Verzeichnisdienst
LDAP://
Objekt in einem LDAP-Verzeichnisdienst
HTTP://
Objekt in einem Webordner bzw. im Exchange-Webstore
COM-Dienste
Objekt
Moniker-Beispiel
Moniker für eine Word-Datei
file://server/freigabe/verzeichnis/datei.xls
Moniker für einen Registrierungsschlüssel
rgy://hkey_local_machine\software\it-visions
Moniker für ein Verzeichnisobjekt
ldap://sonne2000/cn=hs,cn=users,dc=it-visions, dc=de
Tabelle 7.4: Beispiele für Moniker
Moniker für eine WWW-Adresse http://www.windows-scripting.de/book
Weitere Informationen zu Monikern finden Sie in der MSDN Library [MSD01b].
7.5
COM-Dienste
Während Dienste im Rahmen der CORBA-Architektur eine zentrale Rolle einnehmen, ist Dienste der Begriff Dienst in der COM-Spezifikation unscharf. Folglich kommt es zu sehr unterschiedlichen Abgrenzungen der COM-Dienste. Diese sind keineswegs Windows-Dienste, sondern basieren darauf, dass COM-Klassen bestimmte COM-Standardschnittstellen implementieren. Ein COM-Objekt kann einen Dienst nutzen, wenn seine Klasse die für den Dienst notwendigen Schnittstellen implementiert. Als COM-Dienste werden in der Regel betrachtet: 왘 Statischer Methodenaufruf via Standardschnittstelle IUnknown (siehe Kapitel 7.14) 왘 Automation: dynamischer Methodenaufruf über die Standardschnittstelle IDispatch
(siehe Kapitel 7.14) 왘 Namensdienst: Identifizierung bestehender Instanzen (siehe Kapitel 7.17.3) 왘 Sicherheit: Sicherheitseinstellungen für Komponenten (siehe Kapitel 7.22) 왘 Ereignisse: Objekte melden das Eintreten von Zuständen an ihren Client (siehe Kapitel 7.12) 왘 ActiveX-Steuerelemente: visuelle Elemente 왘 ActiveX-Dokumente (Object Linking and Embedding): Zusammensetzung von Doku-
menten aus unterschiedlichen Dokumententypen 왘 Structured Storage: Persistenz für Objekte (siehe Kapitel 7.21) 왘 Distributed COM (DCOM): Zugriff auf entfernte Komponenten (siehe Kapitel 7.16)
Der Microsoft Transaction Server und COM+ erweitern COM um einige weitere Dienste (siehe Kapitel 7.24 und 7.25).
7.6
COM-Konfigurationsdaten
Die Informationen über die Komponenten und deren Konfiguration müssen an einem zentralen Ort gespeichert werden. Konfigurationsspeicher für COM war bis Windows XP allein die Registrierungsdatenbank. Ab Windows XP können Konfigurationsdaten auch in XMLKonfigurationsdateien im Pfad der Anwendung gespeichert werden. Die ursprünglichen Pläne eines in den Active Directory-Verzeichnisdienst integrierten Class Store sind bisher entgegen anders lautender Vorankündigungen nicht umgesetzt worden.
COM in der Registrierungsdatenbank
77
7 Das Component Object Model (COM)
7.6.1
Die Registrierungsdatenbank als Konfigurationsspeicher
Folgende Orte in der Registrierungsdatenbank enthalten für COM relevante Informationen: 왘 HKEY_CLASSES_ROOT (äquivalent zu HKEY_LOCAL_MACHINE\software\classes)
ist der Hauptstandort für COM-Informationen. 왘 HKEY_LOCAL_MACHINE\software\Microsoft\OLE enthält globale COM-Konfigura-
tionseinstellungen. 왘 HKEY_LOCAL_MACHINE\software\microsoft\rpc enthält die Konfiguration der DCOM-
Netzwerkprotokolle. Referenz
HKEY_ CLASSES_ ROOT
Dieses Buch dokumentiert nur ausgewählte Schlüssel und Unterschlüssel. Die MSDN Library enthält eine komplette Referenz der COM-Registrierungsdatenbankschlüssel [MSD01e]. Allgemeine Informationen zur Registrierungsdatenbank als Informationsspeicher für COM gibt es in [MS01f]. HKEY_CLASSES_ROOT Der Inhalt des Registrierungsdatenbankwurzelschlüssels HKEY_ CLASSES_ROOT ist sehr unübersichtlich, weil dort verschiedenartige Informationen abgelegt sind: 왘 Dateierweiterungen (File Extension Keys): Da diese mit einem Punkt beginnen, stehen 왘 왘 왘 왘
sie am Anfang der Liste (z.B. .wri). Die den Dateierweiterungen zugeordneten Dateitypen (z.B. wrifile für die Erweiterung .wri) ProgIDs der COM-Klassen (z.B. Word.Document.8) Moniker-Typen, z.B. HTTP://, FTP://, LDAP://, OUTLOOK:// Unterschlüssel, in denen andere COM-Bausteine registriert sind (CLSID, Interface, AppID, CATID, TypeLib). Es wäre besser gewesen, für alle diese Informationstypen solche Unterschlüssel zu bilden, weil die Registrierungsdatenbank dann übersichtlicher wäre.
7.6.2
XML-Konfigurationsdateien
Manifest
Windows „Whistler“ (Windows XP und Windows Server 2003) unterstützen auch die Ablage von COM-Konfigurationsdaten in XML-Dateien. Diese XML-Dateien heißen Manifeste.
Assembly
Gleichzeitig wird ein neues Konzept in COM eingeführt: Eine Assembly ist eine feste Ansammlung von einer oder mehreren Komponentendateien. Eine Assembly hat eine Konfigurationsdatei, die Assembly Manifest heißt. Ein Assembly Manifest umfasst folgende Daten: 왘 Ein Name der Assembly 왘 Eine Versionsnummer 왘 Die Typangabe „win32“ 왘 Liste der Komponentendateien, die zu der Assembly gehören 왘 COM-Konfigurationsdaten, die COM für die Lokalisierung und Aktivierung dieser
Komponenten benötigt 왘 Liste der abhängigen Assemblies – jeweils mit Versionsnummer
78
Komponentenarten
Eine Anwendung besitzt eine XML-Datei, die Application Manifest heißt. Ein Application Application Manifest Manifest umfasst folgende Daten: 왘 Ein Name der Anwendung 왘 Eine Versionsnummer 왘 Liste der abhängigen Assemblies – jeweils mit Versionsnummer
Ein ähnliches Konzept wird auch im .NET Framework verfolgt. Dort werden auch die Namen Assembly und Manifest verwendet. Das kann zu Verwirrung führen, da ein .NETManifest anders ist als ein COM-Manifest.
7.7
Komponentenarten
Bezüglich der Art und Weise, wie und wo COM-Komponenten gestartet werden, unterscheidet man verschiedene Arten von COM-Komponenten: 왘 prozessintern (engl. in-process, kurz: in-proc) 왘 prozessextern (engl. out-process, kurz: out-proc) 왘 lokal (engl. local) 왘 entfernt (engl. remote)
Prozessinterne Komponenten laufen im Prozess des COM-Clients, während prozessexterne Komponenten in einem separaten Prozess mit einem eigenen Adressraum ausgeführt werden. Da prozessexterne COM-Komponenten keinen gemeinsamen Adressraum mit dem COM-Client besitzen, ist der Datenaustausch zwischen COM-Client und COM-Server sehr viel aufwändiger und damit langsamer als bei prozessinternen Komponenten. Prozessexterne Komponenten haben jedoch auch Vorteile: Ein Absturz der Komponente reißt nicht zwangsläufig auch den gesamten COM-Client in den Abgrund. Prozessexterne Komponenten sind also robuster. Außerdem können sie unabhängig von einem Client gestartet werden.
Prozessintern versus prozessextern
Eine lokale Komponente läuft auf demselben Rechner wie der COM-Client, eine entfernte Lokal versus Komponente auf einem anderen System. Eine Komponente, die ein entfernter COM-Server entfernt ist, muss natürlich immer in einem eigenen Prozess laufen, da ein Prozess mit einem rechnerübergreifenden Adressraum nicht möglich ist. Arten des Prozeduraufrufs Der direkte Aufruf einer Unterroutine ist nur dann stan- LPC dardmäßig möglich, wenn die Unterroutine im gleichen Adressraum wie die aufrufende Routine liegt. Man spricht dann von einem Local Procedure Call (LPC). Nur In-processKomponenten erfüllen diese Anforderung. Sobald die aufzurufende Unterroutine in einem anderen Prozess liegt, läuft sie in einem anderen Adressraum und ist daher über LPC nicht mehr erreichbar. Der Aufruf einer Unterroutine in einem anderen Adressraum wird Remote Procedure Call RPC (RPC) genannt. Dabei wird üblicherweise davon ausgegangen, dass diese Unterroutine sich auch auf einem anderen Rechner befindet. In COM wird ein RPC aber auch bei der Verwendung von Objekten in Out-process-Kom- LRPC ponenten auf demselben Rechner und zwischen verschiedenen Threads innerhalb eines
79
7 Das Component Object Model (COM)
Prozesses eingesetzt. Da allerdings die Inter-process-Kommunikation noch wesentlich einfacher ist als die Inter-system-Kommunikation, spricht man in solchen Fällen von einem Lightweight RPC (LRPC) oder unechtem RPC. Die grundsätzlichen Herausforderungen sind aber ähnlich wie beim echten RPC. Zusätzlich gilt es beim echten RPC jedoch, die Netzwerklast möglichst gering zu halten. Marshalling
Marshalling Der Funktionsaufruf erfolgt beim RPC/LRPC durch Nachrichtenaustausch. Der Vorgang ist aber für den Aufrufer und Empfänger transparent, d.h., er unterscheidet sich in der Form nicht von dem Aufruf der gleichen Funktion auf dem lokalen Rechner. Die Verteiltheit soll allenfalls am Performance-Unterschied erkennbar sein.
Proxy und Um einen RPC/LRPC auszuführen, ist es notwendig, den Funktionsnamen und die ParaStub meter in eine Nachricht (Paket) zu verpacken, die über das Netzwerk dem entfernten Sys-
tem bzw. dem anderen Prozess zugestellt wird. Ebenso müssen die Rückgabewerte nach Ende der Prozedur an den Aufrufer zurückgegeben werden. Eine besondere Herausforderung sind dabei Zeiger. Hier müssen Speicherbereiche übergeben werden, da eine Übergabe eines Zeigers zwischen Prozess- und Systemgrenzen hinweg sinnlos wäre. Der Vorgang der Parameterübergabe wird als Marshalling bezeichnet und findet im so genannten Proxy statt. Auf der Gegenseite erfolgt im Stub ein DeMarshalling. Das Format, in dem die Daten übertragen werden, heißt Network Data Representation (NDR). Für Proxy und Stub sind auch einige andere Bedeutungen im Umlauf. So wird der Marshaller auf der Client-Seite auch Client-Stub oder Server-Proxy (Stellvertreter des Servers) genannt, während die Gegenseite jeweils analog Server-Stub oder Client-Proxy genannt wird. Bild 7.4: Ablauf eines RPC
Client Unterprogrammaufruf
Server
Proxy Marshaling
Stub Unmarshaling
Marshaling
Kern Nachrichten senden
Unterprogrammaufruf
Rückgabewerte
Rückgabewerte
Unmarshaling
Kern Nachrichten empfangen
Nachrichten senden
Nachrichten empfangen
Netzwerk
Proxys und Stubs
Proxy- und Stub-Objekte Proxys bzw. Stubs sind in COM/DCOM selbst COM-Objekte. Die COM-Bibliothek ole32.dll enthält für die meisten COM-Standardschnittstellen bereits fertige Proxy- und Stub-Objekte. Es gibt drei Möglichkeiten des Marshalling für benutzerdefinierte Schnittstellen (siehe auch [GRM97]): 왘 Standard Marshalling
IDL-basiert
80
Bei diesem Verfahren wird der so genannte MIDL-Compiler eingesetzt, um Proxy und Stub automatisch zu generieren. Dazu wird eine Schnittstellenbeschreibung in der Interface Definition Language (IDL) benötigt (zu IDL und MIDL siehe Kapitel 7.13).
Verpackungsformen
왘 TypLib Marshalling
Für das Marshalling von IDispatch-Schnittstellenzeigern sind keine eigenen Proxy-/Stub- IDispatchObjekte nötig, da der so genannte Automations-Marshaller (auch: Universal Marshaller) basiert von COM diese Aufgabe übernimmt. Er wird von Microsoft in Form der OleAut32.dll bereitgestellt. 왘 Custom Marshaller
Für spezielle Anwendungsfälle besteht auch die Möglichkeit, das Marshalling selbst zu Individuell implementieren. Custom Marshaller können bislang allerdings ausschließlich in C++ implementiert werden. Für einige wichtige Klassen liefern die Hersteller jedoch Custom Marshaller mit. Microsoft liefert im Rahmen der Data Access Components einen Custom Marshaller für die Klasse ADODB.Recordset, die relationale Tabellen speichern kann. Proxy und Stub in Visual Basic Hochsprachen wie Visual Basic erzeugen Proxy- und Stub-Objekte automatisch. Ein Scriptprogrammierer braucht sich um das Marshalling nicht zu sorgen, da er sowieso nur IDispatch nutzen kann.
7.8
Verpackungsformen
Eine sich aus COM-Klassen zusammensetzende COM-Komponente bildet eine abgeschlos- COMsene Einheit, die als solche in binärer Form in einer Datei im Dateisystem gespeichert wird. Dateien Eine solche Komponentendatei enthält die Definition der Klassen und den Programmcode. Hier können jedoch keine Instanzen der Klassen gespeichert werden. Es gibt inzwischen vier Dateiformen (Physical Packaging), die COM-Komponenten enthal- Dateiarten ten können: 왘 Dynamic Linking Libraries (.dll/.ocx) 왘 Ausführbare Windows-Dateien (.exe) 왘 Java-Klassen (.class) 왘 Scriptdateien (Scriptlets oder Windows Script Components genannt; .sct und .wsc)
Dabei ist .dll die häufigste Verpackungsform. Nicht jede .exe-, .dll- oder .class-Datei ist jedoch eine COM-Komponente. Die Dateierweiterung .ocx wird dagegen nur für COMDLLs verwendet, die ActiveX-Steuerelemente enthalten. Windows Script Components (WSCs) sind in Scriptsprachen geschriebene COM-Kompo- Script Comnenten. Der Begriff WSC steht jedoch weder allgemein für Komponenten, die von Scripts ponents aus genutzt werden können, noch für die Bausteine der Windows Scripting-Architektur. Nur mit Microsoft Visual J++ können Java-Klassen erzeugt werden, die auch COM-Kom- J++ ponenten sind. Da Microsoft die Weiterentwicklung von J++ nach einem Rechtsstreit mit Sun eingestellt hat, ist diese Variante von COM-Komponenten unwichtig. Microsoft bietet aber einen Migrationspfad von J++ zu Microsoft .NET unter dem Namen JUMP an. In Anlehnung an den Begriff COM-Server spricht man auch von EXE-Servern für eine Komponente in einer .exe-Datei bzw. von DLL-Servern für eine Komponente in einer .dll-Datei.
81
7 Das Component Object Model (COM)
Inhalt einer COM-DLL Eine COM-DLL erkennt man daran, dass sie die vier folgenden DLL-Funktionen (DLL-Einsprungpunkte) exportiert: Registrie- 왘 DllRegisterServer rung
Diese Funktion dient der Registrierung (d.h. der Eintrag in die Registrierungsdatenbank) der Komponente. Sie wird von der COM-Bibliothek aufgerufen. Es ist Aufgabe der Komponente, die Registrierung selbst zu implementieren.
Deregistrie- 왘 DllUnregisterServer rung
Diese Funktion dient der Deregistrierung (d.h. die Entfernung aus der Registrierungsdatenbank) der Komponente. Sie wird von der COM-Bibliothek aufgerufen. Es ist Aufgabe der Komponente, die Deregistrierung selbst zu implementieren.
Instanz erzeugen
Entfernbarkeit
왘 DllGetClassObject
Diese Funktion liefert einen Zeiger auf die Class Factory (siehe Kapitel 7.17) für eine bestimmte COM-Klasse zurück. Der Client kann danach die Class Factory aufrufen, die im Auftrag des Clients eine Instanz der COM-Klasse erzeugt. 왘 DllCanUnloadNow
Mit dieser Funktion kann die COM-Bibliothek erfragen, ob die DLL nicht mehr gebraucht wird. Dies ist dann der Fall, wenn keine Instanzen von COM-Klassen in dieser Komponente mehr benutzt werden. Dazu gibt es in jeder Instanz eine Referenzzählung. Diese wird später im Zusammenhang mit der Standardschnittstelle IUnknown erläutert (Kapitel 7.14).
Bild 7.5: Betrachtung einer COMDLL mit dem Werkzeug „Dependency Walker“ (DEPENDS. EXE)
Bei einer COM-EXE findet man diese Funktionen nicht.
82
Verpackungsformen
Bild 7.6: Betrachtung einer COMEXE mit dem Werkzeug „Dependency Walker“ (DEPENDS. EXE)
7.8.1
EXE-Server im Vergleich zu DLL-Server
Ein EXE-Server hat gegenüber einem DLL-Server den Vorteil, dass die COM-Komponente EXE vs. DLL unabhängig von einem Client gestartet und beendet werden kann. So kann ein EXE-Server schon gestartet werden, bevor es einen Client gibt. Bei der ersten Instanziierung eines Clients erfolgt der Aufruf dann wesentlich schneller, als wenn die Komponente erst dann geladen werden müsste. Eine Komponente in Form einer COM-EXE kann auch als Windows-Dienst laufen. Der Nachteil von EXE-Servern ist jedoch, dass diese immer in einem eigenen Prozess laufen, was Geschwindigkeitsnachteile bei jedem einzelnen Methodenaufruf mit sich bringt.
7.8.2
Der Zusammenhang zwischen Komponentenart und Verpackungsform
Die Verpackungsform der Komponente hat Einfluss auf die Komponentenart: 왘 Scriptlets sind immer prozessintern. 왘 Eine COM-EXE ist immer eine prozessexterne Komponente.
Versionsnummer und andere Metainformationen
왘 Eine COM-DLL ist normalerweise eine prozessinterne Komponente. Allerdings kann
eine COM-DLL mit Hilfe eines so genannten Surrogat-Prozesses auch in einem eigenen Prozess laufen. Ein Surrogat-Prozess ermöglicht es einem DLL-Server, in einem eigenständigen Prozess zu laufen.
83
7 Das Component Object Model (COM)
Bild 7.7: Zusammenhang zwischen Komponentenart und Verpackungsform
lokal
In-Process
Out-Process
COM-EXEs sollen aussterben
entfernt
nicht
.DLL .OCX .WSC
möglich
.EXE
.EXE
.DLL/.OCX/.WSC (wenn mit SurrogatProzess)
.DLL/.OCX/.WSC (wenn mit SurrogatProzess)
Es ist Zielsetzung von Microsoft, die Verpackungsform und die Aktivierungsform zunehmend voneinander zu trennen. Die Zukunft soll den COM-DLLs gehören – COM-EXEs sind eine von Microsoft zum Aussterben verdammte Art.
7.8.3
Zusatzinformationen
Es ist üblich, in den erweiterten Dateiattributen der .dll- und .exe-Dateien Informationen über die Datei zu speichern, z.B. den Hersteller, die Versionsnummer und weitere Kommentare. Diese Informationen werden von den Werkzeugen wie dem Microsoft COM Viewer allerdings nicht angezeigt. Sie können diese Daten entweder über die Eigenschaften der Komponentendatei selbst oder aber über das Werkzeug COM-Explorer (siehe Kapitel 18 „Werkzeuge“) einsehen. Bild 7.8: Attribute einer typischen COM-DLL (Eigenschaftenfenster der Datei)
84
Registrierung von Komponenten
7.9
Registrierung von Komponenten
Bevor Komponenten auf einem Rechnersystem benutzt werden können, müssen sie regist- Komponenriert werden, d.h., es müssen die passenden Einträge für Objekte, Schnittstellen etc. in der tenregistrierung Registrierungsdatenbank erzeugt werden. Die Registrierung erfolgt bei den verschiedenen Komponenten-Dateitypen unterschiedlich: 왘 COM-EXE-Dateien sollten sich beim ersten Aufruf selbst registrieren. Einige erwarten
für den Registrierungsvorgang die Kommandozeilenoption /RegServer. Mit /UnregServer wird die Registrierung aufgehoben. 왘 Komponenten in .dll- und .ocx-Dateien sowie .sct- und .wsc-Dateien werden mit dem Kommandozeilentool regsvr32.exe registriert. regsvr32.exe stößt den Aufruf der exportierten DLL-Funktionen DllRegisterServer bzw. DllUnRegisterServer in der Komponenten-DLL an. Fehlerursachen Die erfolgreiche Registrierung der Komponente ist eine notwendige, Abhängige aber nicht hinreichende Bedingung für das Funktionieren der Komponente. So kann eine Komponenten Komponente andere Komponenten benötigen, die nicht vorhanden sind. Eine häufige Ursache für das Fehlschlagen der Komponentenregistrierung besteht darin, dass DLLs, von denen die Komponenten abhängig sind, nicht vorhanden sind. Eine Hilfe bei der Suche nach Abhängigkeitsproblemen ist das Werkzeug Dependency Walker (siehe Kapitel 18 „Werkzeuge“). Der Dependency Walker zeigt die Abhängigkeiten zwischen DLLs, wobei die Abhängigkeitsinformationen in so genannten Importlisten innerhalb jeder DLL gespeichert sind. Zu beachten ist aber, dass die DLL-Importlisten keine COM-Technologie sind. Man kann anhand der Listen nur erkennen, welche Abhängigkeiten zu Nicht-COM-DLLs existieren. Dagegen kann man aber nicht erkennen, welche COM-DLLs oder anderen COM-Komponenten eine DLL benutzt, weil diese Funktionalität innerhalb der COM-Spezifikation nicht vorgesehen ist. Einige Komponenten können nur funktionieren, wenn unter HKEY_CLASSES_ROOT\ Lizenz Licenses eine entsprechende Lizenz eingetragen ist. Zukunft Es gab Gerüchte, dass Microsoft die Registrierungsdatenbank in Windows 2000 Class Store durch einen Klassenspeicher (Class Store) im Active Directory ablösen wollte. Dies wurde und DOTNET nicht realisiert. Im .NET Framework wird die Registrierungsdatenbank nicht mehr benötigt: Ein pfadbasierter Suchmechanismus und Konfigurationsdateien im XML-Format übernehmen die Aufgaben der Registrierungsdatenbank im .NET-Komponentenmodell.
7.10 COM-Klassen Es gibt in COM zwei Arten von Klassen. Sie unterscheiden sich darin, wer eine Instanz der COM-Klassen Klasse erzeugen kann: 왘 (Öffentlich) erzeugbare Klassen (creatable classes) können direkt durch einen COM-
Client erzeugt werden. 왘 Nicht (öffentlich) erzeugbare Klassen (non-creatable classes) können nur von Instanzen
anderer COM-Klassen der gleichen Komponente erzeugt werden.
85
7 Das Component Object Model (COM)
Man setzt gelegentlich öffentlich vor die Begriffe erzeugbare/nicht erzeugbare Klasse, um klarzustellen, dass sich die Erzeugbarkeit nur auf den COM-Client bezieht. Selbstverständlich sollte eine Klasse zumindest immer durch eine andere Klasse derselben Komponente selbst erzeugbar sein. Eine Klasse, die weder durch den COM-Client noch innerhalb der Komponente selbst erzeugbar ist, ist nicht sinnvoll, weil sie nicht verwendet werden kann. Erzeugbare Klassen
In der Regel verfügt eine Komponente nur über sehr wenige erzeugbare Klassen. Die meisten Klassen einer Komponente sind von bestimmten Initialisierungen abhängig, die durch die Instanziierung bzw. durch die Initialisierung in Folge der Instanziierung einer zentralen Stammklasse vorgenommen werden. Erzeugbare Klassen sind oft die Stammklassen von Objektmodellen (vgl. Kapitel 7.26). Ein COM-Objekt ist eine Instanz einer COM-Klasse. Dabei ist es in der Regel gewünscht, dass es mehr als nur eine Instanz jeder Klasse geben kann. Bezeichner für Klassen Es gibt drei verschiedene Arten von Bezeichnern für Klassen, wobei eine einzelne COM-Klasse alle drei Arten von Bezeichnern haben kann: 왘 Ein Class Identifier (CLSID) 왘 Ein Programmatic Identifier (kurz: ProgID) 왘 Ein Friendly Class Name
Diese Konzepte werden im Folgenden beschrieben.
7.10.1 CLSIDs, CoClass
Klassenidentifikation mit CLSIDs
Ein Class Identifier (CLSID) ist ein GUID für eine Klasse. Nicht jede COM-Klasse verfügt jedoch über einen CLSID. CLSIDs werden nur für so genannte CoClasses vergeben, für die in der Schnittstellendefinition (vgl. Kapitel 7.13) eine explizite Klassendefinition (CoClass genannt) vorliegt. Da, wie in Kapitel 7.11 beschrieben, Schnittstellen und nicht Klassen das Element für den Zugriff auf Objekte in COM sind, ist eine explizite Klassendefinition via CoClass mit CLSID nur für zwei Arten von Klassen notwendig: 왘 Für erzeugbare Klassen 왘 Für Klassen, die Ereignisse aussenden
Alle anderen Klassen können, müssen aber nicht als CoClass definiert werden.
7.10.2 ProgIDs
86
Programmatic Identifier
Ein Programmatic Identifier (kurz: ProgID) ist eine Zeichenkette, die mit einer CLSID assoziiert werden kann. Die ProgID kann ebenso wie die CLSID benutzt werden, um auf eine Klasse zuzugreifen. Die COM-Bibliothek setzt eine ProgID mit Hilfe der Funktion CLSIDFromProgID() in eine CLSID um. Eine ProgID hat die Form KomponentenName. KlassenName.Version. Die Angabe einer Versionsnummer ist dabei optional. Eine ProgID ohne Versionsnummer heißt VersionIndependentProgID. Die Namensvergabe der ProgID ist leider nur eine Konvention, kein Automatismus. Daher gibt es auch ProgIDs, die nur aus dem Klassennamen bestehen (z. B. ADsSecurity, ADsSID, vgl. Kapitel 11.2 „ADSI“).
COM-Klassen
Eine ProgID kann man sich wesentlich einfacher merken als eine lange CLSID. Zweck der ProgID ist es, dem Benutzer (Programmierer) den Zugriff auf COM-Klassen zu vereinfachen. Eine ProgID ist jedoch weniger präzise als eine CLSID: Sie ist nicht weltweit eindeutig. Die ProgID kann jeder COM-Programmierer frei wählen; es besteht die Gefahr, dass mehrere Programmierer für unterschiedliche Klassen die gleiche ProgID verwenden! Leider gibt es keine Konsistenzprüfung bezüglich des Aufbaus einer ProgID. Komponentenerzeuger sind daher nicht gezwungen, sich an die oben genannte Konvention KomponentenName.KlassenName zu halten. 왘 So kann eine Klasse in der ProgID einen Namen bekommen, der nicht dem Namen
in der Typbibliothek entspricht. 왘 Es ist auch möglich, dass Klassen, die in einer Datei (also in einer Komponente) ent-
halten sind, in der ProgID verschiedene Komponentennamen erhalten. 왘 Manche ProgIDs bestehen auch nur aus einem Klassennamen (z.B. eine ProgID wie
ADsSID).
Der COM Runtime sind diese Inkonsistenzen egal, weil intern sowieso nur mit eindeutigen CLSIDs gearbeitet wird. Sie sollten sich jedoch bei selbst erstellten Komponenten an die Konvention halten, dass jede COM-Datei genau einen Komponentennamen hat und der Klassenname der Typdefinition entspricht. Sie machen es damit dem Anwender leichter. Es gibt leider viele Komponentenprogrammierer, die sich nicht an diese Konvention halten.
7.10.3
Friendly Class Name
Neben der CLSID und der ProgID kann es noch eine weitere Bezeichnung für eine Klasse Friendly Class Name geben. Diese Bezeichnung ist ein beliebiger Text und heißt Friendly Class Name. Dieser Friendly Class Name weicht leider häufig von der ProgID ab. So ist beispielsweise die Klasse {3FA7DEB3-6438-101B-ACC1-00AA00423326} der ProgID MAPI.Session zugeordnet, als Friendly Class Name ist jedoch Active Messaging Session Object eingetragen. Dieser Friendly Class Name wird vom Microsoft COM Viewer (siehe Kapitel 18 „Werkzeuge“) zur Anzeige verwendet.
7.10.4
Klassen in der Registrierungsdatenbank
CLSIDs sind im Registrierungsdatenbankschlüssel HKEY_CLASSES_ROOT\CLSID abgelegt. Es würde dem Anwender das Verständnis der Zusammenhänge erleichtern, wenn für jede COM-Klasse eine CoClass existierte. Komponentendatei Wichtigste Aufgabe des CLSID-Schlüssels ist die Bindung an eine LocalServer32 COM-Komponentendatei sowie an eine Typbibliothek. Bei In-process-Komponenten steht und InProcServer32 der Verweis auf die implementierende Datei im Unterschlüssel InProcServer32. Bei Outprocess-Komponenten steht der Verweis auf die implementierende Datei im Unterschlüssel LocalServer32. Sofern beide Einträge angegeben sind, wird die Out-process-Komponente bevorzugt. Es ist nicht möglich, dass der Pfad zu der Datei als UNC-Pfad angegeben wird, selbst dann nicht, wenn der UNC-Pfad auf das lokale System verweist.
87
7 Das Component Object Model (COM)
ProgIDs
ProgIDs in der Registrierungsdatenbank Die ProgIDs befinden sich direkt unterhalb von HKEY_CLASSES_ROOT und machen diesen Hauptordner daher sehr unübersichtlich. Ein ProgID-Schlüssel enthält als einzigen Pflichteintrag den Verweis auf die zugehörige CLSID. Eine VersionIndependentProgID (eine ProgID ohne Versionsnummer) enthält, sofern mehrere Versionen der COM-Klasse installiert sind, im Unterschlüssel CurVer die ProgID der aktuellsten Version dieser Klasse.
Friendly Class Name
Friendly Class Name in der Registrierungsdatenbank Der Friendly Class Name ist als Standardattribut des CLSID-Schlüssels gespeichert. Weitere Werte Weiterhin enthält ein CLSID-Schlüssel die in nachstehender Tabelle aufgelisteten Werte.
Tabelle 7.5: Unterschlüssel einer CLSID
88
Schlüssel
Erläuterung
AppID
AppID der COM-Anwendung, zu der die Klasse gehört
AutoConvertTo
CLSID der Klasse, an die alle Aufrufe weitergeleitet werden sollen
AuxUserType
Kurzname der Klasse
Control
Identifiziert eine Klasse als ein ActiveX-Steuerelement
DefaultIcon
Verweis auf ein Symbol zur grafischen Repräsentation von Instanzen der Klasse
ImplementedCategories
Liste der COM-Kategorien, zu denen die Klasse gehört
InprocHandler
Verweis auf In-process-Handler (16 Bit)
InprocHandler32
Verweis auf In-process-Handler (32 Bit)
InprocServer
Verweis auf In-process-Komponente (16 Bit)
InprocServer32
Verweis auf In-process-Komponente (32 Bit)
Insertable
Zeigt an, dass diese Klasse per OLE in Dokumente eingefügt werden kann
Interface
Liste der implementierten Interfaces in Form von IIDs. Dieser Unterschlüssel wird leider in der Praxis nicht verwendet.
LocalServer
Verweis auf implementierende Out-process-Komponente (16 oder 32 Bit)
LocalServer32
Verweis auf implementierende Out-process-Komponente (32 Bit)
ProgID
Programmatic Identifier (ein Alias für eine CLSID in Form einer Zeichenkette)
RequiredCategories
Liste der COM-Kategorien, zu denen der aufrufende Client gehören muss
TypeLib
LibID der zugehörigen Typbibliothek
ToolBoxBitmap32
Verweis auf eine Bitmap zur Darstellung der Klasse in einer Toolbox (gilt hauptsächlich für visuelle, also ActiveX-Komponenten)
TreatAs
CLSID einer Klasse, die diese Klasse emulieren kann
Verb
Liste zu dieser Klasse gehörender Menüeinträge
Version
Versionsnummer
COM-Schnittstellen
Schlüssel wie Insertable und Control stellen eine Kategorisierung dar, die jedoch veraltet ist. Heute ist es üblich, COM-Kategorien zu verwenden. Für die Abbildung der n-zu-m-Verknüpfung zwischen Klassen und Schnittstellen ist unterhalb der CLSID ein Unterschlüssel mit dem Namen Interface vorgesehen. In der Praxis wird dieser Schlüssel jedoch nicht benutzt. Die implementierten Interfaces einer Klasse können durch IUnknown::QueryInterface() erfragt werden.
Interfaces
7.11 COM-Schnittstellen Das zentrale Element in der COM-Architektur sind nicht die Klassen, sondern die Schnittstellen. Eine Schnittstelle definiert eine Menge von Attributen, Methoden und Ereignissen. Eine COM-Schnittstelle ist ein abstraktes Gebilde. Sie wird implementiert durch eine COM-Klasse. COM-Klassen implementieren eine oder mehrere COM-Schnittstellen; COM unterstützt also Mehrfachschnittstellen. Klassen sind bildlich gesehen eine Klammer um eine Menge von Schnittstellen. Man bezeichnet COM auch als schnittstellenbasiertes Programmieren.
Schnittstellen als zentrales Element in COM
Als Instanz einer Klasse erhält ein COM-Objekt ausnahmslos alle Schnittstellen, die die COM-Klasse implementiert. Die Funktionalität eines COM-Objekts ergibt sich also aus der Gesamtfunktionalität aller Schnittstellen. Der Objektkatalog in Visual Basic 6.0 und VBA erzeugt durch die Verheimlichung der Existenz von Schnittstellen bzw. durch die Erhebung aller Nichtstandardschnittstellen zu „Klassen“ Verwirrung. Der comTLBrowser unterscheidet konsequent zwischen Klassen und Schnittstellen. Weitere Informationen zu diesen beiden Tools finden Sie im Kapitel 18 „Werkzeuge“.
7.11.1
Standardschnittstelle einer COM-Klasse
Jede Klasse besitzt eine Standardschnittstelle, die verwendet wird, wenn keine Schnittstelle explizit verlangt wird. Leider verbirgt der Microsoft-Objektkatalog (vgl. Kapitel 18 „Werkzeuge“) diese Standardschnittstelle vor dem Entwickler. Einige Sprachen (z.B. Visual Basic) fragen bei der Objektaktivierung immer nach dieser Standardschnittstelle. Die Bezeichnung Standardschnittstelle einer Klasse sollte nicht mit den so genannten COMStandardschnittstellen (siehe Kapitel 7.15) verwechselt werden. Viele Mechanismen basieren auf der Implementierung bestimmter, von Microsoft vorgegebener Schnittstellen (z.B. IUnknown, IDispatch, IPersist). Diese COM-Standardschnittstellen müssen in Bezug auf eine konkrete Klasse keineswegs zwingend die Standardschnittstelle dieser Klasse sein.
89
7 Das Component Object Model (COM)
7.11.2 IID
Namensgebung
Jede Schnittstelle besitzt einen GUID, der Interface Identifier (IID) genannt wird, sowie einen textlichen Namen.
Namens- Bei der Namensgebung ist es üblich, die Namen der Schnittstellen mit einem großen I beginnen gebung zu lassen. Sofern die Interface-Namen vor Attributen und Methoden genannt werden, werden
diese durch zwei Doppelpunkte getrennt vorangestellt (z.B.: ISchnittstelle1::Methode()). Die Standardschnittstelle sollte den Namen der Klasse mit einem vorangestellten großen I tragen (Beispiel: Die Klasse File verfügt über die Standardschnittstelle IFile.) Mit Visual Basic 6.0 erstellte Komponenten bilden den Namen der Standardschnittstelle einer Klasse mit einem vorangestellten Unterstrich aus dem Klassennamen (Beispiel: File hat die Standardschnittstelle _File). In der Entwicklungsumgebung der Visual Basic-Vollversion werden die führenden Unterstriche jedoch verborgen, so dass auch hier der Unterschied zwischen Klasse und Schnittstelle verwischt wird. Sichtbar sind alle Schnittstellen im comTLBrowser (siehe Kapitel 18 „Werkzeuge“).
7.11.3 Interface-IDs
Schnittstellen in der Registrierungsdatenbank
Schnittstellen werden ebenfalls in der Registrierungsdatenbank verzeichnet. Unterhalb von HKEY_CLASSES_ ROOT\interface befindet sich eine Liste der Interface-IDs (IIDs) aller installierten Komponenten. Zu einem Interface werden in der Registrierungsdatenbank nur wenige Informationen abgelegt: 왘 Die CLSID der zugehörigen Proxy- und Stubklasse 왘 Optional die Anzahl der Methoden, die die Schnittstelle definiert 왘 Optional die LibID der zugehörigen Typbibliothek
7.11.4 Liste von Zeigern
Virtuelle Tabellen
In der binären Form sind Schnittstellen die aus der C++-Welt bekannten „Tabellen virtueller Funktionen“ (kurz: vTable oder VTBL). Eine vTable-Struktur ist eine Liste von Zeigern auf die Implementierung von Funktionen (vgl. folgende Abbildung). Zwischen dem Zeiger auf eine Schnittstelle und der vTable liegt eine weitere Zwischenstufe. Das, was der COMClient als Schnittstellenzeiger besitzt, ist nicht der Zeiger auf die vTable, sondern ein Zeiger auf einen Zeiger auf eine vTable. Die Position einer Methode innerhalb der vTable wird über einen Funktionsoffset ermittelt, der die relative Position innerhalb der vTable angibt.
Binär- Die vTables in COM entsprechen den vTables des Microsoft C++-Compiler (vgl. [GRU00], standard Seite 262). Eine vTable ist das bestimmende Element des Binärstandards von COM. Diese
vTable-Struktur macht COM programmiersprachenunabhängig, da jede Sprache COM nutzen kann, die diese vTable-Struktur verwenden kann.
90
COM-Schnittstellen
COMClient
COM-Server (Komponente) Instanz 1 Schnittstelle1
Schnittstelle2
QueryInterface()
Implementierung
AddRef()
Implementierung
Release()
Implementierung
GetIDsOfNames()
Implementierung
Invoke()
Implementierung
Zeiger auf vTable
GetTypeInfoCount()
Implementierung
Referenzzähler
GetTypeInfo()
Implementierung
Zeiger auf vTable
Methode1()
Implementierung
Methode2()
Implementierung
Methodex()
Implementierung
Zeiger auf vTable Referenzzähler
Instanz 2 Schnittstelle1
Schnittstelle2
vTable
Zeiger auf vTable Referenzzähler
Schnittstellenzeiger
COM-Klasse
Referenzzähler
Bild 7.9: Interner Aufbau einer Komponente aus vTables
vTable QueryInterface() AddRef()
Implementierung
usw.
7.11.5
Die Grauzone zwischen Klasse und Schnittstelle
Während es in der Komponententheorie und auch in der COM-Spezifikation eine klare Klasse verAbgrenzung zwischen Klasse und Schnittstelle gibt, wird dieser Unterschied in der Praxis sus Schnittstelle der COM-Programmierung stark verwischt. Dabei muss man zwei Blickrichtungen unterscheiden: die Sicht der Implementierung des COM-Servers und die Sicht der Implementierung des COM-Clients. Sicht des Servers Von der Implementierung der Komponente aus betrachtet gibt es in Sicht des der Regel nur Klassen. Programmiersprachen wie C, C++, Java und Visual Basic kennen das Servers Konzept der expliziten Schnittstellendefinition nicht. Die Sprachen verfügen nicht über ein Schlüsselwort, um eine Schnittstelle explizit zu definieren. In den Sprachen können nur Klassen definiert werden, deren Mitglieder genau eine Schnittstelle bilden. Mehrfachschnittstellen können nicht definiert werden. Dennoch existiert in jeder dieser Sprachen die Möglichkeit, im Zuge der Erzeugung von COM-Komponenten Mehrfachschnittstellen zu generieren. Schnittstellen werden dabei als abstrakte Basisklassen definiert (d.h. also als Klassen mit Funktionsrümpfen, aber ohne Implementierung). Eine Klasse x, die Mehrfachschnittstellen besitzen soll, erbt von einer oder mehreren dieser abstrakten Basisklassen (y und z). Die Klassen y und z bilden dann jeweils eine Schnittstelle in der Klasse x. Dieser umständliche Weg wurde gewählt, um Programmiersprachen COM-implementierungsfähig zu machen, unter der Bedingung, dass der Sprachumfang nicht oder nur gering erweitert werden muss. Sicht des Clients Der COM-Client dagegen sieht nichts von der Implementierung einer Sicht des Komponente. Er sieht lediglich das binäre Format der Komponente und gegebenenfalls eine Clients Typinformation (vgl. Kapitel 7.13). Diese sprachunabhängigen Darstellungsformen kennen sehr wohl das Konzept von expliziten Schnittstellen und Mehrfachschnittstellen. Programmiersprachen besitzen zur Verwaltung von Objekten Objektvariablen oder Objektzeiger. Diese zeigen bei der Arbeit mit COM aber nicht auf Objekte, sondern auf einzelne
91
7 Das Component Object Model (COM)
Schnittstellen. Dabei ist jeweils nur eine Schnittstelle (d.h. eine bestimmte Untermenge der Gesamtfunktionalität) zu einem bestimmten Zeitpunkt im Zugriff. Um auf andere Schnittstellen zugreifen zu können, muss die Schnittstelle gewechselt werden (Interface Casting). Sofern nicht die Programmiersprache ein besonderes Konstrukt für Schnittstellenzeiger anbietet, merkt der Programmierer nicht, ob er mit Objekten oder Schnittstellen arbeitet. Er merkt das allenfalls am Namen. Schnittstel- Schnittstellenwechsel (Interface Casting) COM unterstützt den Wechsel der Schnittlenwechsel stelle mit dem Standardmechanismus IUnknown::QueryInterface() (vgl. Kapitel 7.15).
Einige Programmiersprachen können diesen Mechanismus bedienen, andere – z. B. Scriptsprachen – nicht. Eine Klasse hat immer die Möglichkeit, neben dem vorgeschriebenen Standardmechanismus zum Schnittstellenwechsel auch einen benutzerdefinierten Mechanismus anzubieten. Dabei bietet die Klasse ein Attribut oder eine Methode an, die einen Zeiger auf die andere Schnittstelle liefert (aus der Sicht des Programmierers ist der Zeiger – wie oben erläutert – ein Zeiger auf ein Objekt, nicht auf eine Schnittstelle). Dieses Verfahren kann selbstverständlich jeder COM-Client – also auch eine Scriptsprache – nutzen, der überhaupt in der Lage ist, auf Attribute und Methoden von COM-Objekten zuzugreifen. Für den Programmierer der Komponente bedeutet dies jedoch zusätzlichen Aufwand. Die Komponente Collaboration Data Objects (CDO) in der Version 3.0 besitzt einen solchen benutzerdefinierten Mechanismus zum Schnittstellenwechsel.
7.11.6
Mangelnde Selbsterkenntnis bei den Schnittstellen
Schnittstel- Den Namen der Klasse, zu der das Objekt gehört, kennt eine COM-Schnittstelle nicht. Die len ohne Abbildung der 1-zu-n-Beziehung zwischen Klasse/Objekt und Schnittstellen kann nicht Zusammenhang von einer Komponente erfragt werden. Wenn ein COM-Client also von einem bestehenden
Objekt einen Schnittstellenzeiger bekommt, dann kann der Client nicht ohne weiteres erkennen, ob es sich dabei um den Zeiger auf eine andere Schnittstelle des gleichen Objekts oder um den Zeiger auf eine Schnittstelle eines anderen Objekts handelt. Der Client, der den IUnknown-Standardmechanismus zum Schnittstellenwechsel verwendet, könnte höchstens den Typ des neuen Schnittstellenzeigers dazu verwenden, auf einem anderen Schnittstellenzeiger mit IUnknown::QueryInterface() nach diesem Typ zu fragen. Sofern der dann ermittelte Schnittstellenzeiger mit dem zuvor von einem Objekt gelieferten Schnittstellenzeiger identisch ist, weiß der COM-Client, dass es sich um zwei Schnittstellen ein und desselben Objekts handelt. Dies ist ein komplizierter Weg, der zudem voraussetzt, dass der COM-Client den Typ des neuen Schnittstellenzeigers kennt. Der Mensch Sie werden sich jetzt fragen, warum es denn nachteilig ist, dass eine Schnittstelle nichts über ist der Leid- die Klasse weiß, die sie implementiert. Das Problem liegt nicht auf technischer Ebene, denn tragende
COM selbst benötigt den Zusammenhang zwischen Klasse und Schnittstelle nicht. Das Problem liegt allein bei dem Menschen, der einen COM-Client für diese Komponente schreiben will. Ein Programmierer muss wissen, über welche COM-Klasse eine bestimmte COM-Schnittstelle erreichbar ist, sonst erhält er nämlich keinen Schnittstellenzeiger zu dieser Schnittstelle.
Typinformationen
92
Typinformationen Die COM-Schöpfer haben mit den Typinformationen, die in Kapitel 7.13 vorgestellt werden, eine Möglichkeit vorgesehen, den Zusammenhang zwischen Klassen und Schnittstellen auf formelle Art zu beschreiben. Leider ist es weder zwingend, alle Klassen und Schnittstellen vollständig zu beschreiben, noch überhaupt Typinformationen zu liefern.
COM-Schnittstellen
So beschränken sich viele Typinformationen darauf, die Schnittstellen der instanziierbaren Klassen zu listen; alle anderen Schnittstellen sind oft ohne die Klassennamen definiert. Leidtragender ist der Komponentennutzer, der im Zweifel durch Ausprobieren herausbekommen muss, wie er einen Zeiger zu einer bestimmten Schnittstelle bekommt. Spätestens an diesem Punkt ist eine absolut saubere Dokumentation einer COM-Komponente notwendig, da es sonst zu großen Begriffsverwirrungen kommt. Leider findet man solche Dokumentationen heute noch sehr selten mit der Konsequenz, dass die Einarbeitung in die meisten Komponenten unnötig verlängert wird. Registrierungsdatenbank Die Registrierungsdatenbank stellt zwar mit dem Unterschlüssel Interfaces einer CLSID grundsätzlich eine Möglichkeit bereit, die implementierten Schnittstellen einer Klasse zu listen, jedoch wird von dieser Möglichkeit in der Praxis kein Gebrauch gemacht, zumal dies ja auch nur für die CoClasses von Nutzen wäre, da andere COM-Komponenten nicht in der Registrierungsdatenbank verzeichnet werden. Ein Client könnte auch versuchen, alle in der Registrierungsdatenbank gelisteten IIDs durch Ausprobieren mit IUnknown::QueryInterface() gegen eine Instanz einer bestimmten Klasse zu testen. Dies ist jedoch eine sehr langwierige Aufgabe (zu QueryInterface() siehe Kapitel 7.15.1).
Die Registrierungsdatenbank hilft nicht weiter
Schnittstellen in Scriptsprachen Das Ganze wird etwas einfacher, wenn man Sprachen betrachtet, die den Wechsel der Schnittstelle mit dem COM-Standardmechanismus gar nicht unterstützen. Zu diesem Typus von Programmiersprachen gehören die bislang vorhandenen ActiveX-Scriptsprachen. Diese Sprachen können immer nur das Standardinterface einer COM-Klasse sehen. Da sie keine weiteren Schnittstellen sehen können, ist aus der Blickrichtung dieser Sprachen ein Objekt das Gleiche wie eine Schnittstelle. Die Standardschnittstelle muss zudem eine bestimmte Form haben; sie muss nämlich eine direkte Implementierung der Standardschnittstelle IDispatch sein oder aber von IDispatch abgeleitet sein. Der dahinter stehende Mechanismus heißt COM-Automation (vgl. Kapitel 7.14 und 7.15.2).
Scriptsprachen sehen nur Klassen
Schnittstellenwechsel in Scriptsprachen Sofern
alle
beteiligten
Schnittstellen Interface
IDispatch unterstützen, können auch Scriptsprachen dazu gebracht werden, die Schnittstelle Casting in
zu wechseln. Es gibt dazu zwei Möglichkeiten:
Scriptsprachen
왘 Das Objekt selbst stellt einen eigenen Mechanismus bereit, der dem Aufrufer einen Zeiger
auf eine andere Schnittstelle liefert. Aus der Sicht der Scriptsprache besteht kein Unterschied darin, ob der Zeiger ein Zeiger auf ein neues Objekt oder ein Teil des alten Objekts ist. Wie bereits erwähnt, ist dies in CDO 3.0 genau auf diese Weise implementiert. 왘 Active Scripting-Sprachen können mit einer einzigen Zusatzkomponente durchaus dazu gebracht werden, bei allen COM-Klassen mit Mehrfachschnittstellen die Schnittstelle zu wechseln (vgl. [WES99c]). Diese Zusatzkomponente muss dann aber auf allen Systemen, auf denen ein derart geschriebenes Script eingesetzt werden soll, existieren.
7.11.7
Bullet-and-Stick-Diagramme
Wenn die Zuordnung zwischen Klassen und Schnittstellen grafisch dargestellt werden soll, Grafische werden so genannte Bullet-and-Stick-Diagramme (siehe folgende Abbildung) verwendet. Darstellung Solche Bullet-and-Stick-Diagramme können beispielsweise mit der Diagramming-Soft-
93
7 Das Component Object Model (COM)
ware Microsoft Visio erstellt werden. Leider gibt es in der üblichen grafischen Notation keine Unterscheidung zwischen Klasse und Objekt: Beide werden als ein Kasten dargestellt. Da – wie oben geschildert – aus der Sicht des Scriptings die Schnittstellen eine untergeordnete Rolle spielen, wird in der Darstellung der Objektmodelle auf die explizite Darstellung der Schnittstellen verzichtet. Bild 7.10: Bullet-andStick-Diagramm einer COM-Klasse mit Standardschnittstelle IUnknown und drei benutzerdefinierten Schnittstellen
IUnknown
ISchnittstelle1 ISchnittstelle2
Klassenname
ISchnittstelle3
7.12 Klassenmitglieder Eine Klasse bzw. eine Schnittstelle besitzt Mitglieder. In COM gibt es drei verschiedene Typen: Attribute, Methoden und Ereignisse. Die Klassenmitglieder näher betrachtet
Auch wenn COM-Clients einen Unterschied zwischen Attributen, Methoden und Ereignissen sehen, so sind doch alle diese Mitglieder intern in Form von Methoden implementiert. So ist der Attributzugriff aus der Sicht von COM der Zugriff auf ein Paar von zwei Methoden, wobei die eine den Attributwert ausliest (die „Get“-Methode) und die andere den Attributwert setzt (die „Set“-Methode). Dies ist die einzig mögliche Implementierung, da sonst der COM-Client immer die Möglichkeit haben müsste, direkt in den Adressraum des COM-Servers zu schreiben.
Attribute Entwicklungsumgebungen wie Visual Studio bieten dem Programmierer dennoch eine Attriwerden in butsicht auf Basis von Typinformationen (vgl. Kapitel 7.13). Vom Programmierer kodierte Methoden umgesetzt Attribute werden automatisch in ein passendes Paar von Methoden umgewandelt. Wenn im
Folgenden also nur noch von Methoden die Rede ist, sind die Attribute keineswegs vergessen worden. Item-Attribut mit Parametern
94
Attribute mit Parametern Verwirrend ist es für den Entwickler, Attribute mit Parametern zu sehen, denn es gibt in der objektorientierten Lehre normalerweise keine Attribute mit Parametern. In COM ist dies jedoch möglich und an einer Stelle auch sehr gebräuchlich: Objektmengen (Objektmengen) enthalten ein Attribut Item für den direkten Zugriff auf die enthaltenen Objekte (im Einzelfall auch auf die elementaren Datentypen). Item hat dabei einen Parameter zur Spezifikation des gewünschten Objekts anhand eines Schlüssels. Vorzufinden sind sowohl numerische als auch alphanumerische Schlüssel. Sehen Sie Item eher wie ein Array, dann können Sie das Vorgehen besser mit dem objektorientierten Weltbild vereinen.
Typinformationen
Reduzierung der Rundgänge Bei prozessexternen Komponenten besteht eine enorme Optimierungsmöglichkeit darin, die Anzahl der Methodenaufrufe zu minimieren: Da auch jeder Zugriff auf ein Attribut in einen Methodenaufruf umgesetzt wird, ist es günstiger, eine einzige Methode mit n Parametern aufzurufen, anstatt zunächst n Attribute zu setzen und dann eine Methode ohne Parameter aufzurufen. Dieser Aspekt ist jedoch irrelevant, wenn COM-Client und COM-Server im gleichen Adressraum liegen. Ereignisse COM unterstützt das Aussenden von Ereignissen durch COM-Server und die Ereignisse Behandlung von Ereignissen durch COM-Clients. COM-Ereignisse werden beispielsweise eingesetzt zur Meldung von Zwischenständen bei länger andauernden Operationen oder zur Realisierung asynchroner Methodenaufrufe, bei denen der COM-Client direkt nach dem Aufruf einer Methode die Kontrolle zurückerhält. Über das Ergebnis der von ihm aufgerufenen Methode wird er nach Abschluss der Verarbeitung per Ereignis informiert. In Zusammenhang mit COM-Ereignissen wird folgende Terminologie verwendet: 왘 Event Publisher (Ereignisanbieter) ist ein Objekt, das ein Ereignis aussendet. Man kann
den Publisher auch den Event Server nennen.
Publisher, Subscriber und Event Sink
왘 Event Subscriber (Event Client, Ereigniskonsument) ist ein Objekt, das auf das Eintreten
eines Ereignisses in einem Event Publisher wartet. 왘 Event Sink ist die Ereignisbehandlungsroutine im Event Subscriber, die in Reaktion auf
das Ereignis Programmcode ausführt. Die Realisierung von Ereignissen basiert ebenfalls auf Methoden und der Unterstützung Connection bestimmter Standardschnittstellen im COM-Client und im COM-Server. Der COM-Client Points liefert dem COM-Server einen Zeiger auf eine bestimmte Schnittstelle. Wenn im COM-Server ein Ereignis ausgelöst wird, ruft der COM-Server eine Methode der ihm gelieferten Schnittstelle auf. In diesem Zusammenhang sind auch Verbindungspunkte und die Standardschnittstellen IConnectionPoint und IConnectionPointContainer zu nennen; sie sollen hier nicht näher betrachtet werden. COM-Clients, die Ereignisse abfangen wollen, müssen selbst COM-Komponenten sein. Event SubScripting Hosts unterstützen in der Regel nur Ereignisse ihrer eingebauten Objekte. Eine scriber beim Scripting Ausnahme bilden bisher nur der Windows Script Host (WSH) und der System Scripting Host (SSH), die Ereignisse beliebiger automationsfähiger Komponenten abfangen können. Der Connection Point-Mechanismus ist ein Ereignismechanismus mit fester Kopplung, bei COM+dem sowohl COM-Client als auch COM-Server zu allen Zeiten ausgeführt werden müssen. Ereignisse Lose gekoppelte Ereignisse werden erst durch COM+ ab Windows 2000 möglich.
7.13 Typinformationen Typinformationen sind eine formale Beschreibung der Klassen mit ihren Schnittstellen und Typinformationen deren Mitgliedern. Typinformationen umfassen insbesondere: 왘 Namen der Klassen 왘 Namen der Schnittstellen 왘 Von einer Klasse implementierte Schnittstellen
95
7 Das Component Object Model (COM)
왘 Namen der Mitglieder einer Schnittstelle 왘 Attribute mit ihrem Datentyp 왘 Methoden und Ereignisse mit den zugehörigen Parametern sowie dem Rückgabewert
(jeweils inklusive Datentyp) Für das statische Binden werden Typinformationen benötigt, um die Einsprungadressen zu ermitteln. Das dynamische Binden kommt dagegen ohne Typinformationen aus. Gleichwohl bilden Typinformationen auch beim dynamischen Binden die Grundlage für die Eingabehilfen, welche von modernen Entwicklungsumgebungen (z. B. Visual Studio 6.0) zur Verfügung gestellt werden. Schließlich kann ein COM-Client eine Komponente durch Typinformationen auch zur Laufzeit erforschen. Leider sind aus der Sicht von COM selbst nicht alle oben genannten Typinformationen zwingend notwendig. Sie sind allesamt hilfreich für den Menschen, der eine Komponente nutzen will. Daran denken jedoch viele Komponentenentwickler nicht, die nur unvollständige Typinformationen zu ihren Komponenten liefern. Speicherformen
Speicherformen Es gibt drei Formen der Speicherung von Typinformationen: IDLDateien, Header-Dateien und Typbibliotheken. Ein COM-Client bedient sich entweder einer Header-Datei oder einer Typbibliothek, um an Typinformation zu kommen. Eine IDL-Datei kann er nicht verwenden. IDL-Dateien werden eingesetzt, um daraus HeaderDateien und Typbibliotheken automatisch zu erzeugen. Header-Dateien werden von C/C++ verwendet und enthalten die notwendigen Deklarationen in Form von Quellcode im C/C++-Stil. Visual Basic und Scriptsprachen verwenden Typbibliotheken.
Bild 7.11: Speicherformen für Typinformationen
IDL COM-Viewer
MIDL-Compiler
96
MIDL-Compiler
Header-Datei
Typbibliothek
C++
Visual Basic
Typinformationen
7.13.1
Interface Definition Language (IDL)
Es gibt eine formale Sprache zur Beschreibung von Typinformationen – die Interface Defi- IDL nition Language (IDL); sie wurde von der Open Software Foundation (OSF) entwickelt und garantiert eine programmiersprachenunabhängige Definition von Schnittstellen. IDL basiert auf der Syntax der Programmiersprache C. Microsoft verwendet eine erweiterte Form, die Microsoft Interface Definition Language (MIDL). Eine ältere Bezeichnung dafür ist auch Object Definition Language (ODL). Eine IDL-Datei kann Informationen über alle kompletten Komponenten enthalten. Sie hat die Dateierweiterung .idl. IDL-Dateien können problemlos mit Visual C++ erstellt werden. Die Ausdrucksfähigkeit von IDL reicht aus, um das Schema einer Komponente komplett zu beschreiben. Allerdings werden in der COM-Praxis die Typinformationen in der Regel nur dazu benutzt, die Schnittstellen zu beschreiben. Die Typinformationen beschreiben nur das, was der Client von der Komponente sehen soll. Die in der Komponente enthaltenen Objektmodelle sind nicht immer anhand der Typinformationen erkennbar. Grundsätzlich jedoch ermöglichen Typinformationen unter Einsatz eines entsprechenden Tools wie dem Microsoft Objektkatalog die Navigation in den Objektmodellen einer Komponente.
Typinformation, Schema und Objektmodell
Beispiele Es folgen einige IDL-Beispiele. Das erste Beispiel zeigt die Definition einer von Beispiel 1 IDispatch abgeleiteten Schnittstelle mit Namen IWSHShell. [ odl, uuid(F935DC21-1CF0-11D0-ADB9-00C04FD58A0B), helpstring("Shell Object Interface"), hidden, dual, oleautomation ] interface IWSHShell : IDispatch { [id(0x00000064), propget] HRESULT SpecialFolders([out, retval] IWSHCollection** out_Folders); [id(0x000000c8), propget] HRESULT Environment( [in, optional] VARIANT* Type, [out, retval] IWSHEnvironment** out_Env); [id(0x000003e8)] HRESULT Run( [in] BSTR Command, [in, optional] VARIANT* WindowStyle, [in, optional] VARIANT* WaitOnReturn, [out, retval] int* out_ExitCode); [id(0x000003e9)] HRESULT Popup( [in] BSTR Text, [in, optional] VARIANT* SecondsToWait, [in, optional] VARIANT* Title, [in, optional] VARIANT* Type, [out, retval] int* out_Button);
97
7 Das Component Object Model (COM)
[id(0x000003ea)] HRESULT CreateShortcut( [in] BSTR PathLink, [out, retval] IDispatch** out_Shortcut); [id(0x000003ee)] HRESULT ExpandEnvironmentStrings( [in] BSTR Src, [out, retval] BSTR* out_Dst); [id(0x000007d0)] HRESULT RegRead( [in] BSTR Name, [out, retval] VARIANT* out_Value); [id(0x000007d1)] HRESULT RegWrite( [in] BSTR Name, [in] VARIANT* Value, [in, optional] VARIANT* Type); [id(0x000007d2)] HRESULT RegDelete([in] BSTR Name); }; Listing 7.2: IDL-Beispiel 1: Eine IDL-Schnittstellendefinition Beispiel 2
Das zweite Beispiel demonstriert Versionierung: IWSHShell2 ist eine neuere Version von IWSHShell. IWSHShell2 erbt daher von IWSHShell. [ odl, uuid(24BE5A30-EDFE-11D2-B933-00104B365C9F), helpstring("Shell Object Interface"), hidden, dual, oleautomation ] interface IWSHShell2 : IWSHShell { [id(0x00000bb8)] HRESULT LogEvent( [in] VARIANT* Type, [in] BSTR Message, [in, optional] BSTR Target, [out, retval] VARIANT_BOOL* out_Success); [id(0x00000bc2)] HRESULT AppActivate( [in] VARIANT* App, [in, optional] VARIANT* Wait, [out, retval] VARIANT_BOOL* out_Success); [id(0x00000bc3)] HRESULT SendKeys( [in] BSTR Keys, [in, optional] VARIANT* Wait); }; Listing 7.3: IDL-Beispiel 2: Eine abgeleitete IDL-Schnittstellendefinition
98
Typinformationen
Im dritten Beispiel wird eine Klasse WSHShell definiert, die genau eine Schnittstelle IWSHShell2 Beispiel 3 hat. [ uuid(72C24DD5-D70A-438B-8A42-98424B88AFB8), helpstring("Shell Object") ] coclass WSHShell { [default] interface IWSHShell2; }; Listing 7.4: IDL-Beispiel 3: Eine IDL-Klassendefinition mit einer Schnittstelle
Eine Klasse mit mehreren Schnittstellen sieht man im vierten Beispiel. Eine der Schnittstel- Beispiel 4 len ist dabei die Standardschnittstelle. [ uuid(DFC33154-69A3-43EC-9EE7-BB12C9609E1F), version(1.0) ] coclass AllInOne { [default] interface _AllInOne; interface _IPrinter; interface _IFax; interface _IScanner; }; Listing 7.5: IDL-Beispiel 4: eine IDL-Klassendefinition mit vier Schnittstellen
Mit Hilfe des Werkzeugs COM Viewer können die im Folgenden beschriebenen Typbibliotheken in IDL zurückgewandelt werden.
7.13.2
Typbibliotheken
Eine Typbibliothek (engl. Type Library, kurz: TypeLib) ist die kompilierte Version einer TypeLibs IDL-Datei, die binär gespeicherte Typinformationen enthält. Eine Typbibliothek kann als eigenständige Datei (Dateierweiterungen .tlb und .olb, zum Teil auch .oca oder .rll) oder als Bestandteil einer .dll-, .ocx- oder .exe-Datei realisiert werden. Eine derartige Datei kann mehrere Typbibliotheken enthalten, allerdings unterstützen nicht alle Umgebungen diese Funktion. Der Microsoft-Objektkatalog unterstützt diese Funktion nicht. Typbibliotheken sind für das Funktionieren von COM nicht unbedingt notwendig, bieten Anwendungs jedoch wertvolle Zusatzdienste. Sie wurden für Visual Basic geschaffen, um dieser Sprache, gebiete die keine Header-Dateien einbinden kann, das frühe Binden zu ermöglichen. Ebenso basieren viele Eingabehilfen und Werkzeuge (wie der Microsoft-Objektkatalog und der in diesem Buch vorgestellte comTLBrowser – siehe Kapitel 18 „Werkzeuge“) auf Typbibliotheken. Leider können Typbibliotheken nicht den kompletten IDL-Sprachumfang wiedergeben. Werkzeuge Header-Dateien und Typbibliotheken können mit Hilfe des Microsoft IDL- KonvertieCompiler (MIDL-Compiler) aus IDL-Dateien erzeugt werden. Typbibliotheken lassen sich rungen mit Hilfe des Microsoft COM Viewers in IDL zurückverwandeln. Der COM Viewer enthält
99
7 Das Component Object Model (COM)
dazu eine spezielle Funktion mit dem Namen „View TypeLib“, die ein Fenster mit dem Titel „ITypeLib Viewer“ öffnet. Bild 7.12: Anzeige einer Typbibliothek mit dem TypeLib Viewer des COM Viewer
Symbolische Konstanten
Konstantenlisten Eine Typbibliothek kann neben den Definitionen von Klassen, Schnittstellen und deren Mitgliedern auch symbolische Konstanten enthalten. Symbolische Konstanten (auch Konstantenbezeichnungen genannt) sind Zeichenketten, die einen beliebigen Wert repräsentieren (in der Regel eine Zahl) und als Alias für diesen Wert benutzt werden. Während der eigentliche (numerische) Konstantenwert aus der Sicht des Systems auf das Wesentliche fokussiert, nämlich sich von anderen Werten eindeutig zu unterscheiden, dabei aber wenig Speicherplatz zu verbrauchen, richtet sich eine symbolische Konstante an das Erinnerungsvermögen des Programmierers. Ein Mensch kann sich einen sprechenden Namen besser merken als Zahlen oder Abkürzungen. So repräsentiert beispielsweise die symbolische Konstante vbYes die Zahl 6, die die Visual Basic-Funktion MsgBox() zurückliefert, wenn der Benutzer auf die Schaltfläche Ja geklickt hat. Der Programmcode wird durch symbolische Konstanten lesbarer.
Constant Symbolische Konstanten sind in Konstantenlisten (Constant Enumerations) angeordnet, Enumera- was sinnvoll ist, da es in der Regel einen Block zusammenhängender Konstantenwerte gibt, tions
die in einer bestimmten Methode oder in einem bestimmten Attribut verwendet werden. Dabei sind die Konstanten aus einer Konstantenliste nicht immer als alternative Werte zu sehen. Wenn ein Methodenparameter bzw. ein Attribut Mehrfachwerte erlaubt, spricht
100
Statischer Aufruf versus Automation
man von einem Flag. Ein solches Flag verwendet beispielsweise die VB-Funktion MsgBox() für den Parameter Buttons. Voraussetzung für die Nutzung symbolischer Konstanten ist, dass die jeweilige Umgebung Typbibliotheken auslesen kann. Leider verfügen noch nicht alle Scripting Hosts über diese Fähigkeit. In diesem Fall bleibt dem Entwickler nichts anderes übrig, als die symbolischen Konstanten selbst im Quellcode zu definieren. Während Sie mit dem Microsoft-Objektkatalog jede symbolische Konstante nur einzeln in die Zwischenablage übernehmen können, ermöglicht der comTLBrowser die Übernahme ganzer Konstantenlisten.
Konstantendefinitionen in Typbibliotheken
Typbibliotheken in der Registrierungsdatenbank Die Informationen zu den Typ- TypeLibbibliotheken befinden sich unterhalb des Schlüssels HKEY_CLASSES_ROOT/TypeLib. Dort Schlüssel sehen Sie eine Liste der LibIDs der installierten Typbibliotheken. Es können mehrere Versionen einer Typbibliothek auf einem System parallel bestehen, wobei die Versionsnummer die erste Ebene unterhalb der LibID bildet. Unterhalb der jeweiligen Versionsnummer finden Sie im Standardattribut des Schlüssels /Win32 den Pfad zur Typbibliothek. Die zweite wichtige Information ist das Standardattribut der Versionsnummer. Hier steht eine kurze textliche Beschreibung der Typbibliothek, die als Friendly Name (d. h., es ist eine für einen Menschen bestimmte Information, vgl. Kapitel 7.10.4) der Typbibliothek dient. Diese Zeichenkette wird in der IDL als so genannter Helpstring definiert. Der Mechanismus der COM-Automation (siehe Kapitel 7.14 und 7.15.2) stellt Methoden bereit, um Typinformationen aus Typbibliotheken zur Laufzeit zu ermitteln. Dadurch kann ein COM-Client zur Laufzeit den COM-Server erforschen und „interessante“ Methoden aufrufen.
Dynamische Typinformationen
Bild 7.13: Aufbau der TypeLib-Informationen in der Registrierungsdatenbank anhand der Word-Komponente; die interne Versionsnummer der Typbibliothek entspricht nicht immer der Produktver-sionsnummer (hier 8.1 = 9.0)
7.14 Statischer Aufruf versus Automation COM kennt – wie andere Verteilungsplattformen auch – zwei Formen des Methodenaufrufs: 왘 Dynamischer Aufruf (engl. Dynamic Method Invocation, COM-Automation): Die Ent-
scheidung über den konkreten Methodenaufruf fällt erst zur Laufzeit. Dies ist immer dann nötig, wenn zur Zeit der Kompilierung nicht bestimmt werden kann, welche Methode aufgerufen werden soll. Dies ist insbesondere beim Einsatz von Polymorphismus gegeben und bei interpretierten Sprachen (wie Scriptsprachen), die nicht kompiliert werden. 왘 Statischer Aufruf (engl. Static Method Invocation): Bereits zur Zeit der Kompilierung
ist festgelegt, welche Methoden aufgerufen werden.
Statischer Aufruf versus dynamischer Aufruf
101
7 Das Component Object Model (COM)
Automation Server und Clients
Begriffe Der dynamische Aufruf wird in COM Automation genannt. Ein COM-Server, der Automation unterstützt, ist ein Automation Server. Man spricht auch von automationsfähigen Klassen und automationsfähigen Komponenten, sofern eine Komponente automationsfähige Klassen unterstützt. Ein COM-Client, der Automation nutzt, heißt Automation Client oder Automation Controler. Frühere Begriffe, die Sie aber nicht mehr verwenden sollten, waren OLE Automation, OLE Server und OLE Client/OLE Controler.
Automation versus Automatisierung
Statt des Begriffs Automation werden Sie in anderen Büchern auch Automatisierung lesen. Im Englischen heißt die Technologie Automation. In diesem Buch wird durch Verwendung des Begriffs Automation eine Abgrenzung zum allgemeinen Begriff Automatisierung vollzogen. Automatisierung steht hier allgemein für die programmgesteuerte Ausführung von administrativen Aufgaben.
Geschichte des Begriffs Automation
Statisches und dynamisches Binden in COM
Der Begriff Automation stammt aus der Zeit, in der Dynamic Data Exchange (DDE) und die erste Version von OLE zum Datenaustausch bzw. zur Fernsteuerung von OfficeAnwendungen wie Word und Excel verwendet wurden. Die heutige COM-Automation ist eine Weiterentwicklung der Techniken, die bereits bei OLE eingesetzt wurden. Der Name ist geblieben, obwohl COM-Automation längst in anderen Bereichen als nur in der Fernsteuerung von Office-Anwendungen eingesetzt wird. Binden Binden bedeutet in COM die Zuordnung eines Methodenaufrufs zu einer Adresse in der vTable einer Schnittstelle (zum Begriff „Binden“ siehe auch Anhang A). Der Aufruf ist der folgende Schritt. Ein statischer Aufruf erfordert statisches Binden (frühes Binden, Early Binding), ein dynamischer Aufruf erfordert dynamisches Binden (spätes Binden, Late Binding). Die Unterscheidung zwischen dynamischem und statischem Binden ist Standard in objektorientierten Sprachen. Beim statischen Binden kennt der COM-Client zur Entwicklungszeit die Position (Offset) einer Funktion innerhalb der vTable. Der Offset ist im Binärcode des COM-Clients festgelegt. Der statische Aufruf einer Methode erfolgt zur Laufzeit also über die Startadresse der vTable und den hinterlegten Offset. Die Startadresse der vTable der gewünschten Schnittstelle muss freilich auch beim statischen Binden zur Laufzeit bei der Komponente erfragt werden (vgl. den Abschnitt zu IUnknown im folgenden Kapitel). Auf Grund des direkten Zugriffs auf die vTable heißt das statische Binden auch VTBL Binding. Beim dynamischen Binden ist dagegen der Offset nicht bekannt. Die Bindung erfolgt durch verschiedene Mechanismen erst zur Laufzeit (vgl. den Abschnitt zu IDispatch in Kapitel 7.15). Bewertung Der Vorteil des statischen Aufrufs durch dynamisches Binden ist eindeutig die sehr viel höhere Geschwindigkeit, da der COM-Client die Funktion direkt aufrufen kann. Allerdings ist der statische Aufruf durch statisches Binden unflexibel: Ein COMClient muss bereits zur Entwicklungszeit wissen, welchen Objekttyp er vor sich hat. Wenn Polymorphismus eingesetzt werden soll, ist statisches Binden normalerweise nicht möglich.
102
COM-Standardschnittstellen
Allerdings bildet COM durch die Konzeption der Mehrfachschnittstellen eine Ausnahme. Hier ist ein dynamischer Methodenaufruf mit dem Ziel, Polymorphismus zu realisieren, auch durch statisches Binden möglich.
Ausnahme in COM
Wenn durch einen Methodenaufruf auf zwei Instanzen unterschiedlicher COM-Klassen, die die gleiche Schnittstelle unterstützen, zugegriffen werden soll, muss der Bindungsvorgang nicht dynamisch erfolgen, da der Funktionsoffset (relativ zur vTable der Schnittstelle) zur Entwicklungszeit ermittelt werden kann. Die Bindung ist also statisch möglich; der Methodenaufruf ist dennoch als dynamisch anzusehen, da zur Entwicklungszeit noch nicht feststeht, welche Implementierung aus welcher der beiden Klassen aufgerufen werden wird. Sobald zwei Klassen zwar die gleichen Methoden, diese aber in unterschiedlichen Schnittstellen unterstützen, ist immer dynamisches Binden notwendig, da die Funktionsoffsets verschieden sind. Hiermit haben Sie wieder ein Beispiel kennen gelernt, wie komplex die Welt der Objekte und Komponenten in COM sein kann.
7.15 COM-Standardschnittstellen Microsoft hat inzwischen rund 200 Standardschnittstellen definiert, einen Teil davon bereits Standardim Rahmen der COM-Spezifikation. Standardschnittstellen sind die Basis zur Erbringung schnittstellen von COM-Diensten: Ein COM-Dienst kann nur dann funktionieren, wenn die daran beteiligten Komponenten einheitliche Schnittstellen bieten. Alle Nichtstandard-Schnittstellen heißen benutzerdefinierte Schnittstellen. COM liefert für die Mehrheit der Standardschnittstellen (noch) keine Implementierung. Standardschnittstellen sind in der Regel nur abstrakte Schnittstellendefinitionen; sie müssen also in jedem COM-Client neu implementiert werden. Nur für ausgewählte Standardschnittstellen enthält die COM-Bibliothek Standardimplementierungen. Entwicklungsumgebungen und programmiersprachenspezifische Laufzeitumgebungen stellen auf verschiedene Weisen (z. B. die Visual Basic-Laufzeitumgebung, die Active Template Library in Visual C++) Implementierungen bereit, die übernommen werden können, so dass der Programmierer diese Schnittstellen nicht selbst kodieren muss. Die wichtigste Standardschnittstelle ist IUnknown. Ob etwas eine COM-Klasse ist, kann IUnknown daran festgemacht werden, ob sie IUnknown unterstützt oder nicht. Auf dem zweiten Platz und IDispatch dieser Hitliste liegt IDispatch. Danach kommt lange erst einmal nichts mehr, weshalb dieses Buch sich auf die Darstellung dieser beiden zum Verständnis von COM wichtigsten Schnittstellen beschränkt. Mehr über diese und andere Standardschnittstellen erfahren Sie bei [BOX99] und [EDD00]. Die Typinformationen zu den Standardschnittstellen IUnknown und IDispatch müssen nicht in jede IDL-Datei aufgenommen werden. Dazu kann die Typbibliothek stdole32.tlb importiert werden. Sie können die Datei im COM Viewer (vgl. Kapitel 18 „Werkzeuge“) öffnen, um sich die „rohe“ Definition der beiden Standardschnittstellen anzusehen.
103
7 Das Component Object Model (COM)
7.15.1 Unknown
Statisches Binden mit IUnknown
IUnknown (IID= {00000000-0000-0000-C000-000000000046}) ist die wichtigste Schnittstelle
in COM. Mit Hilfe dieser Schnittstelle können die Zeiger auf die vTables anderer Schnittstellen ermittelt werden. Dabei ist IUnknown die Basis für den statischen Methodenaufruf (VTBL Binding). Im Bullet-and-Stick-Diagramm wird die Schnittstelle IUnknown üblicherweise an exponierter Stelle (oben) auf der Komponente dargestellt, um der Besonderheit dieser Schnittstelle Ausdruck zu verleihen. Es gilt: 왘 Jede COM-Klasse muss eine IUnknown-Schnittstelle besitzen. 왘 Alle COM-Schnittstellen sind von IUnknown abgeleitet. Das gilt sowohl für Standard- als
auch für benutzerdefinierte Schnittstellen. Daher kann auf die Methoden von IUnknown von jeder Schnittstelle aus zugegriffen werden. Die IUnknown-Methoden Die drei von IUnknown definierten virtuellen Methoden müssen daher von jeder einzelnen COM-Schnittstelle bereitgestellt werden. Sie stehen am Anfang der vTable einer jeden Schnittstelle. Üblicherweise erfolgt die Implementierung aber nur einmal pro Klasse. Die Funktionszeiger jeder einzelnen Schnittstelle verweisen dann auf diese Implementierung. QueryInterface()
왘 QueryInterface() ermöglicht die Anfrage an ein COM-Objekt, ob das Objekt eine
bestimmte Schnittstelle unterstützt. Wenn das Objekt das Interface anbietet, liefert Query Interface() einen Zeiger auf die Schnittstelle zurück, sonst den Wert 0.
AddRef()
왘 Jede Schnittstelle benötigt einen Referenzzähler, der angibt, wie oft eine Schnittstelle zum
aktuellen Zeitpunkt benutzt wird. Der Aufruf von AddRef() erhöht diesen Referenzzähler um eins. AddRef() wird automatisch aufgerufen, wenn QueryInterface() Erfolg hat. Ein manueller Aufruf von AddRef() ist nur notwendig, wenn der COM-Client selbst einen Schnittstellenzeiger dupliziert und die Laufzeitumgebung der betreffenden Sprache den Aufruf von AddRef() nicht automatisch vornimmt. Der COM-Server kann die Zählung in diesem Fall nicht vornehmen, da er an der Duplizierung nicht beteiligt ist. Release()
왘 Der Aufruf von Release() vermindert den Referenzzähler der Schnittstelle um eins.
Release() entfernt nicht automatisch das Objekt aus dem Speicher. Ein Objekt kann erst gelöscht werden, wenn der Referenzzähler der Schnittstelle, für die Release() auf-
gerufen wurde, auf 0 steht und die Referenzzähler aller anderen Schnittstellen auch auf 0 stehen. QueryInterface(Schnittstelle1) Schnittstellenzeiger
Bild 7.14: Darstellung des QueryInterface()Mechanismus
Operation 1 COM-Client
2 3 4
QueryInterface(Schnittstelle3)
ISchnittstelle1 ISchnittstelle2
Schnittstellenzeiger
Operation
104
IUnknown
ISchnittstelle3
COMServer
COM-Standardschnittstellen
Einschränkungen Ergebnis der Instanziierung einer Klasse ist in COM immer, dass der vTableCOM-Client einen Zeiger auf die IUnknown-Schnittstelle des erzeugten Objekts erhält. Für Fähigkeit C++- und Java-Programmierer ist IUnknown der zentrale Dreh- und Angelpunkt der COMProgrammierung. Das große Visual Basic und VBA nutzen zwar IUnknown (diese Fähigkeit hat Visual Basic seit Version 4.0), verbergen dies jedoch vor dem Programmierer. Scriptsprachen können IUnknown nicht benutzen, weil sie üblicherweise nicht „vTable-fähig“ sind. vTable-Fähigkeit bedeutet die Unterstützung des komplizierten Mechanismus, um von einem Schnittstellenzeiger über einen Zeiger auf einen weiteren Zeiger zu den Methodenimplementierungen zu gelangen. Nicht vTable-fähig ist gleichbedeutend mit der Unfähigkeit, verschiedene Schnittstellen eines Objekts voneinander unterscheiden zu können, und damit auch der Unfähigkeit, Mehrfachschnittstellen zu nutzen. Das große Visual Basic und VBA können IUnknown aber nur nutzen, wenn es für die Klasse und ihre Schnittstellen eine Typbibliotheksdefinition gibt. In der Regel kompilieren Komponentenentwickler eine Typbibliothek leider nur für automationsfähige Komponenten.
7.15.2
Automation mit IDispatch
Die bisherigen Ausführungen haben gezeigt, dass Scriptsprachen COM gar nicht nutzen IDispatch könnten, wenn es nur IUnknown gäbe. Die Lösung heißt IDispatch (IID = {00020400-00000000-C000-000000000046}). Diese Standardschnittstelle ist die Basis für die COM-Automation, auf der das Active Scripting (siehe Kapitel 7.23) beruht. IDispatch ermöglicht den Aufruf einer Methode über ihren Namen in Textform. Ein Automation-Client muss keinen anderen Schnittstellenzeiger als den von IDispatch kennen und keine anderen Funktionsoffsets als diejenigen der wenigen IDispatch-Methoden. Diese Informationen sind fest in der Laufzeitumgebung der jeweiligen Sprache hinterlegt. IDispatch ist eine Form des dynamischen (späten) Bindens. Der IDispatch-Mechanismus Genauer betrachtet funktioniert der Mechanismus folgendermaßen: 왘 Der Automation-Client beschafft sich zunächst einen Zeiger auf die Standardschnitt-
stelle der Klasse. Dieser Mechanismus ist fest hinterlegt. Der Automation-Client kann nur mit diesem Schnittstellenzeiger arbeiten, sofern die Schnittstelle IDispatch entspricht oder zumindest von IDispatch abgeleitet ist. 왘 Der Automation-Client ruft zunächst die IDispatch-Methode GetIDsOfNames() auf.
GetIDsOf-
왘 Der Methodenaufruf erfolgt dann mit IDispatch::Invoke(), wobei die DispID und die
Invoke()
Dabei übergibt der Client den Namen der gewünschten Methode in Form einer Zei- Names() chenkette. GetIDsOfNames() liefert dem Automation-Client eine so genannte DispatchID (DispID) zurück. Eine DispID ist eine eindeutige Zahl für eine Methode innerhalb einer COM-Schnittstelle. DispIDs sind jedoch keine GUIDs und daher nicht über Schnittstellen hinweg eindeutig. Parameter für die Methode übergeben werden müssen. Die Parameter werden in Form eines Array of Variants übergeben.
105
7 Das Component Object Model (COM)
Variant
Der Datentyp Variant geht auf die Sprache Visual Basic zurück. Ein Variant ist ein universeller Behälter für prinzipiell alle Datentypen. Eine Variant-Variable kann zur Laufzeit zu jedem beliebigen Zeitpunkt ihren Inhaltstyp ändern. Sie trägt auch dazu bei, COM für (Script-)Sprachen zu vereinfachen, die keine strengen Datentypen kennen. Typinformationen zur Laufzeit Weiterhin bietet IDispatch zwei Methoden, um zur Laufzeit Typinformationen auszulesen:
GetTypeInfoCount()
왘 Mit der Methode IDispatch::GetTypeInfoCount() kann ermittelt werden, ob für die
GetTypeInfo()
왘 IDispatch::GetTypeInfo() liefert bei vorhandenen Typinformationen einen Zeiger auf
Klasse Typinformationen verfügbar sind. Der Rückgabewert 1 bedeutet, dass Typinformationen zur Verfügung stehen. 0 bedeutet, dass keine Typinformationen verfügbar sind. die Schnittstelle ITypeInfo(), die ihrerseits dazu dient, Namen und Parameter der implementierten Mitglieder dieser Klasse zu ermitteln. GetTypeInfoCount() und GetTypeInfo() sind für die Funktionsfähigkeit des IDispatchAblaufs nicht notwendig. Diese beiden Methoden werden nur dazu benutzt, dem Entwickler zur Entwicklungszeit Informationen über die verfügbaren Methoden und Attribute bereitzustellen. Die Eingabehilfen verschiedener Entwicklungsumgebungen greifen auf GetTypeInfoCount() und GetTypeInfo() zurück.
Da alle Schnittstellen von IUnknown abgeleitet sein müssen, besitzt natürlich auch eine IDispatch-Schnittstelle die drei IUnknown-Methoden. Diese sind aber für einen Automation-Client ohne Bedeutung. Natürlich können auch vTable-fähige Sprachen IDispatch verwenden. Sie sollten es jedoch nicht tun: Der geschilderte Weg des Methodenaufrufs über die IDispatch-Schnittstelle macht deutlich, dass COM-Automation wesentlich langsamer ist als VTBL Binding. ID Binding
Binden mit bekannter DispID Es gibt einen Weg, die Verwendung von IDispatch etwas zu beschleunigen: Wenn der COM-Client die DispID einer Methode bereits kennt, dann entfällt der Aufruf von GetIDsOfNames() und Invoke() kann direkt verwendet werden. Interpretersprachen, die nur zur Entwicklungszeit binden können, sind dazu angehalten, einmal zur Laufzeit ermittelte DispIDs in einem Cache zu halten und somit eine zweite Anfrage an GetIDsOfNames() zu vermeiden. Kompilierte Sprachen können eine DispID auch schon zur Entwicklungszeit aus einer Typbibliothek ermitteln und in die Binärform eines Clients hineinkompilieren. Dieses Verfahren wird auch als ID Binding bezeichnet. Da ID Binding eine Form des frühen Bindens ist, wird das VTBL Binding zur Abgrenzung vom ID Binding auch als sehr frühes Binden bezeichnet. Grenzen von IDispatch Ein COM-Server kann natürlich neben IDispatch auch benutzerdefinierte Schnittstellen unterstützen. Über die COM-Automation sind jedoch in jedem Fall nur jene Methoden erreichbar, die in IDispatch unterstützt werden. Sofern die benutzerdefinierten Schnittstellen weitere Methoden unterstützen, sind diese nur via IUnknown und VTBL Binding erreichbar. IDispatch konterkariert also den Vorteil der Mehrfachschnittstellen – das ist der Tribut, den man beim Windows Scripting zahlen muss.
106
COM-Standardschnittstellen
Automations-MINFU Leider betreibt Microsoft auch an dieser Stelle wieder ein MIcro- Viele versoft Nomenclature Foul-Up (MINFU, vgl. Erläuterungen in Anhang B) und zeigt sich sehr wirrende Begriffe einfallsreich und wenig konsistent darin, den Unterschied zwischen automationsfähigen und nichtautomationsfähigen Schnittstellen einer Komponente zu dokumentieren. So findet man in der MSDN Library für automationsfähige Schnittstellen z.B. die Begriffe: 왘 ActiveX Programming Objects (XML-Dokumentation im Web Workshop) 왘 Scripting API (WMI-Dokumentation) 왘 Visual Basic Object Model (ASP-Dokumentation)
Dagegen heißen die nichtautomationsfähigen Schnittstellen oft: 왘 COM Programming Interfaces (XML-Dokumentation) 왘 COM API (WMI-Dokumentation) 왘 Non-Automation Interfaces (ADSI-Dokumentation)
Grundsätzlich können Sie als Anhaltspunkt nehmen: Die Verwendung des Begriffs Interface deutet eher auf nichtautomationsfähige Schnittstellen hin, während Objekte über IDispatch angesprochen werden können. Dies entspricht der eher auf Klassen bzw. Objekte gerichteten Sicht der Automation. Aber auch das ist nicht allgemein gültig, denn oft fehlt jeglicher Hinweis auf die IDispatch-Unterstützung. Als wäre es so schwer, jeder Komponentenreferenz IDispatch: Ja|Nein voranzustellen!
7.15.3
Duale Schnittstellen
Ein guter Ansatz ist die Implementierung aller Schnittstellen als so genannte duale Schnitt- Duale stellen. Eine duale Schnittstelle ist eine benutzerdefinierte Schnittstelle, die nicht direkt von Schnittstellen IUnknown, sondern von IDispatch abgeleitet wird. Da IDispatch von IUnknown abgeleitet ist, verfügt eine duale Schnittstelle natürlich auch über die nötige IUnknown-Implementierung. Die vTable einer dualen Schnittstelle besteht also aus mindestens sieben Methoden (drei von IUnknown, vier von IDispatch). Die weiteren Positionen der vTable enthalten dann direkte Zeiger auf die Methoden der Schnittstelle. Eine Klasse kann über mehrere duale Schnittstellen verfügen. Die IDispatch-Implementierung sollte jedoch jeweils dieselbe sein und natürlich sollten über jedes IDispatch::Invoke() alle benutzerdefinierten Methoden aller Schnittstellen zur Verfügung stehen. COM-Clients haben dann die Auswahl, über die vTable direkt auf die benutzerdefinierten Methoden zuzugreifen oder aber über IDispatch::Invoke() den dynamischen Aufruf zu benutzen. Natürlich sollte ein entsprechend mächtiger Client immer den benutzerdefinierten Teil der Schnittstelle verwenden! In der Regel werden heute COM-Objekte mit dualen Schnittstellen generiert. Beispielsweise erzeugt Visual Basic immer duale Schnittstellen für in VB erstellte COM-Klassen.
107
7 Das Component Object Model (COM)
Bild 7.15: vTable einer dualen Schnittstelle
QueryInterface() AddRef()
Methoden von IUnknown
Release() GetIDsOfNames() Invoke() GetTypeInfoCount()
Methoden von IDispatch
GetTypeInfo() Methode_1() Methode_2()
Benutzerdefinierte Methoden
Methode_x()
7.15.4 Erweiterte Version von IDispatch
DispatchEx
IDispatchEx ist eine verbesserte Version von IDispatch, die zusätzlich folgende Funktionen
unterstützt: 왘 Ermittlung der Namen der von der Klasse bereitgestellten Methoden zur Laufzeit – auch
ohne Typbibliothek 왘 Hinzufügen von Methoden zur Laufzeit 왘 Entfernen von Methoden zur Laufzeit
IDispatchEx wird bisher leider nur von wenigen COM-Klassen implementiert.
7.16 Distributed COM (DCOM) DCOM
Das Distributed Component Object Model (DCOM) ist ein Zusatzdienst zum Component Object Model (COM), der es ermöglicht, COM-Komponenten nicht nur auf dem lokalen Rechner, sondern auch auf entfernten Systemen zu benutzen (Fernaufruf oder engl. Remoting). Ein früherer Name von DCOM ist Network OLE. DCOM wurde mit NT 4.0 ausgeliefert, später aber auch als Add-on zu Windows 95 verfügbar gemacht. Seitdem gehört DCOM zum Standard jeder Betriebssystemversion bei Microsoft.
OSF DCE
Dem Component Object Model und dem DCOM-Dienst liegt die Distributed Computing Environment (DCE) der Open Software Foundation (OSF) zu Grunde. DCE definiert eine Umgebung für verteilte Systeme mit Werkzeugen und Diensten für verteilte Anwendungen. Zentraler Dienst im DCE ist der Remote Procedure Call (RPC).
Eigenschaften Fernaktivierung
Jede COM-Komponente kann ohne Veränderungen sofort mit DCOM eingesetzt werden. Es müssen lediglich die Sicherheitseinstellungen entsprechend konfiguriert werden. DCOM unterscheidet: 왘 Ausgehende Fernaktivierung – ein lokaler Client nutzt eine entfernte Komponente 왘 Eingehende Fernaktivierung – ein entfernter Client benutzt eine lokale Komponente
108
Distributed COM (DCOM)
7.16.1
DCOM-Protokoll
DCOM ist ein Dienst, der mit Hilfe des DCOM-Protokolls realisiert wird. Das DCOM-Pro- DCOMtokoll basiert auf den im Distributed Computing Environment (DCE) spezifizierten Protokoll Remote Procedure Calls (RPC) und wird auch Object RPC (ORPC) genannt. Es ist im ISO/ OSI-Referenzmodell auf der Schicht 7 (Anwendungsebene) angesiedelt und transportprotokollunabhängig; es kann auf verschiedenen Transportprotokollen (z.B. TCP/IP, UDP/IP, IPX/SPX, AppleTalk), aber auch auf Anwendungsprotokollen wie HTTP aufsetzen.
7 Anwendungsschicht (Application Layer)
6 Darstellungsschicht (Presentation Layer)
RPC ...
5 Kommunikationssteuerungsschicht (Session Layer)
4 Transportschicht (Transport Layer)
3 Netzwerkschicht (Network Layer)
2 Sicherungsschicht (Data Link Layer)
1 physikalische Schicht (Physical Layer)
Bild 7.16: Einordnung von DCOM in das ISO/OSIReferenzmodell
DCOM
TCP/UDP/...
...
Anwendungsorientierte Schichten
Transportorientierte Schichten
IP/... ... ...
Eigenschaften Zu den Funktionen von DCOM gehört eine verteilte Speicherverwal- Ping tung (Distributed Garbage Collection), die über einen Ping-Mechanismus realisiert wird. Ein COM-Client muss regelmäßig eine kurze Nachricht an den Computer senden, der den COM-Server hostet. Wenn dieser Ping mehrmals nicht eintrifft, dann reduziert COM den Referenzzähler der verwendeten Instanz des COM-Servers. Wenn der Referenzzähler den Wert 0 erreicht hat, verwirft COM die Instanz des COM-Servers. Der DCOM-Ping-Mechanismus ist nicht mit dem auf dem ICMP-Protokoll basierenden Netzwerk-Ping im TCP/IPProtokollstack zu verwechseln. Methodenaufrufe sind in COM/DCOM immer synchron. Zwar gibt es auch eine asyn- Synchron chrone Form des RPC, diese wird von DCOM jedoch nicht verwendet.
7.16.2
DCOM-Installation und -Konfiguration
DCOM gehört ab Windows 98 zum Basisumfang von Windows. Auf Windows 95 kann DCOM Installation durch Installation des Internet Explorers ab Version 4.0 oder durch ein spezielles DCOM-Add- und Konfiguration on für Windows 95 ermöglicht werden. Für das in Windows 98 enthaltene DCOM gibt es ein Update. Alte 16-Bit-Windows-Betriebssysteme können über die alte Remote Automation-Technik auf COM-Komponenten zugreifen.
109
7 Das Component Object Model (COM)
DCOM DCOM-Konfiguration Um DCOM auf einem PC zu ermöglichen, muss der Registriezulassen rungsdatenbankschlüssel HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Ole\Enable
DCOM auf den Wert Y (für Yes) gesetzt sein. Mit einem anderen Wert sind weder eingehende noch ausgehende Fernaktivierungen möglich. Lokale Aktivierungen sind dennoch erlaubt, sofern die der Klasse zugeordneten Startberechtigungen dies für den Benutzerkontext des Clients erlauben. Auf einem Windows 95/98/ME-System muss zusätzlich der Schlüssel HKEY_LOCAL_ MACHINE\SOFTWARE\Microsoft\Ole\EnableRemoteConnections auf Y gesetzt werden, damit COM-Objekte angesprochen werden können. Die für die DCOM-Kommunikation zu verwendenden Protokolle befinden sich im Registrierungsdatenbankschlüssel HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc. Ports
Jeder Prozess, der ein COM-Objekt enthält, erhält dynamisch eine Portnummer zwischen 1024 und 65535. Das nachfolgende REGEDIT4-Listing zeigt die notwendigen Registrierungsdatenbankeinträge, um die Ports einzuschränken. Im folgenden Beispiel werden nur die Ports 4000–6000 erlaubt. Alle zuvor genannten Einstellungen können auch über das DCOM Configuration Utility (DCOMCNFG) vorgenommen werden. REGEDIT4 [HKEY_LOCAL_MACHINE\Software\Microsoft\Rpc\Internet] "Ports"="4000-6000" "PortsInternetAvailable"="Y" "UseInternetPorts"="Y" Listing 7.6: Registrierungsdatenbaneinstellungen zur Einschränkung der DCOM-Ports [CD: /install/ com/portbeschraenkung.reg]
7.16.3
DCOM im Internet
DCOM kann nicht nur im LAN und WAN, sondern prinzipiell auch im Internet genutzt werden, da TCP/IP als Netzwerkprotokoll unterstützt wird. Dem stehen jedoch Firewalls entgegen, welche die für das DCOM-Protokoll notwendigen TCP-Ports sperren oder IP-Adressen aus Sicherheitsgründen umsetzen (DCOM-Stubs speichern die IP-Adressen). Oft kann oder will man aber die Konfiguration einer Firewall nicht ändern, um DCOM den Weg freizumachen. COM Internet Service (CIS)
RDS
110
Microsofts Lösung dafür heißt COM Internet Service (CIS) (in der deutschen Version: COM-Internetdienste). CIS meint das Tunneling des DCOM-Protokolls im Hypertext Transfer Protocol (HTTP). Dabei wird jedoch nur die erste DCOM-Nachricht in eine HTTP-Nachricht verpackt. Alle weiteren DCOM-Nachrichten werden direkt via Port 80 versendet. Auch das wird von einigen Firewalls nicht erlaubt. Eine weitere Einschränkung ist, dass CIS nur in Verbindung mit einem Internet Information Server ab Version 4.0 auf dem CIS-Server funktioniert. Ein Windows 9x/ME-Rechner kann also kein CIS-Server sein. Die COM-Komponente, die auf CIS aufsetzt, heißt Remote Data Service (RDS). RDS wird in diesem Buch nicht weiter behandelt. Nähere Informationen hierzu finden Sie in der MSDN Library [MSL00].
Distributed COM (DCOM)
CIS-Installation CIS ist in folgenden Systemen enthalten: 왘 NT 4.0 durch Installation von Service Pack 4
CIS-Installation
왘 Windows 95 ab DCOM Version 1.2 왘 Windows 98 ab DCOM Version 1.3 왘 Windows ME 왘 Windows 2000 (Installationsoption) 왘 Windows XP (Installationsoption) 왘 Windows Server 2003 (Installationsoption) 왘 Windows Vista (Installationsoption)
CIS-Konfiguration Auf einem Windows 2000-Server erfolgt durch Auswahl der Instal- CIS-Konfigulationsoption Netzwerk-dienste/COM Internetdiensteproxy nicht nur die Installation von ration CIS, sondern auch die korrekte Konfiguration des IIS. Auf einem NT 4.0-Server müssen Sie selbst sicherstellen, dass 왘 der ISAPI-Filter rpcproxy.dll aktiviert ist; 왘 unterhalb der Standardwebsite ein virtueller Pfad mit Namen RPC existiert, der eine
Kopie der rpcproxy.dll enthält und auf dem Ausführungsrechte aktiviert sind; 왘 CIS aktiviert ist (in DCOMCNFG müssen Sie die Option Internetdienste auf diesem Rechner grundsätzlich aktivieren auf der Registerkarte Standardeigenschaften aktivieren); 왘 CIS den Standardprotokollen hinzugefügt ist (der Eintrag Tunneling TCP/IP auf der Registerkarte Standardprotokolle muss hinzugefügt sein, siehe folgende Abbildung). Bild 7.17: Aktivierung von CIS mit Hilfe von DCOMCNFG auf einem NTClient
Im Windows Server 2003 heißt die Installationsoption „RPC over HTTP-Proxy“. Auf dem CIS-Client müssen nur die letzten beiden Schritte durchgeführt werden. Unter ciscnfg.exe Windows 95/98/ME gibt es dafür das Kommandozeilentool ciscnfg.exe.
111
7 Das Component Object Model (COM)
SOAP und XML RPC
Simple Object Access Protocol (SOAP) Die Zukunft der Inter-process-Kommunikation im Internet gehört aber nicht DCOM, sondern dem Simple Object Access Protocol (SOAP). SOAP realisiert einen Fernaufruf auf Basis des Austauschs von XML-Daten. In der Regel, aber nicht zwingend, werden diese XML-Daten mit HTTP übermittelt. SOAP will unabhängig von Plattformen, Komponentenarchitekturen, Programmiersprachen und Firewalls sein. SOAP wird im .NET Framework verwendet und kommt auch im Windows Remote Management (WinRM) zum Einsatz. Weitere Informationen zu SOAP finden Sie bei [SOA01a], [SOA01b] und [DVM00]. XML RPC ist ein alternativer, auch sehr ähnlicher Ansatz zu SOAP [XRP00], der sich nicht durchgesetzt hat.
7.17 Objektaktivierung Aktivierung
Wesentliche Voraussetzung für die Ausführung eines Methodenaufrufs in einer Komponente ist die ordnungsgemäße Aktivierung des Objekts. Das ist notwendig, um einem COM-Client einen Schnittstellenzeiger auf einen bisher von ihm nicht benutzten COMServer zu liefern. Diese Vorgänge sind sehr komplex und sollen hier nur in Grundzügen erläutert werden. COM unterstützt drei Formen der Aktivierung: 왘 Erzeugung neuer Objekte durch Instanziierung von Klassen 왘 Zugriff auf bestehende Instanzen im Speicher 왘 Zugriff auf persistente Objektinstanzen
7.17.1 SCM
Service Control Manager (SCM)
Der Service Control Manager (SCM) ist derjenige Teil der COM-Implementierung, der dafür zuständig ist, Anfragen von COM-Clients nach Schnittstellen entgegenzunehmen und mit einem Zeiger auf die entsprechende Schnittstelle zu antworten. COM-Client und COM-Server kommunizieren aber nicht direkt mit dem SCM; sie rufen Methoden in der COM-Bibliothek auf, die ihrerseits den SCM ansprechen. Der SCM ist kein Object Trader, der in der Lage wäre, eine Anforderung der Form „Liefere mir irgendeine Komponente, die eine Textdatei lesen und schreiben kann und Unicode unterstützt“ zu bearbeiten. Die Auswahl der Komponente muss der Client treffen. Das Component Object Model stellt bislang neben der Kategorisierung von Klassen in Component Categories (siehe Kapitel 7.20) keinen Trading-Mechanismus bereit. Auch der Standort der Komponente muss dem Client bekannt sein. Oft werden daher selbst programmierte Trader-Objekte zwischen Client und Server geschaltet.
RPCSS.EXE
112
Der SCM ist in rpcss.exe implementiert und im Task-Manager sichtbar, da er automatisch gestartet wird. Der SCM verwendet als festen TCP-/UDP-Port den Port Nummer 135. Nur so weiß ein SCM immer, wie er den SCM-„Kollegen“ auf einem entfernten Rechner erreichen kann. Sofern ein Client eine Ferninstanziierung fordert, hat diese Anforderung für den SCM Vorrang vor den in der Registrierungsdatenbank konfigurierten lokalen Komponenten.
Objektaktivierung
7.17.2
Erzeugung neuer Instanzen
Die Funktion der COM-Bibliothek, mit der eine neue Instanz angefordert werden kann, CoCreateheißt CoCreateInstance(). Wichtigste Parameter von CoCreateInstance() sind die CLSID Instance() der gewünschten Klasse und die IID der gewünschten Schnittstelle; optional ist der Name des Computers, von dem das Objekt angefordert werden soll. Sofern ein Client eine ProgID statt einer CLSID übergibt, muss diese vorher umgewandelt werden. Scriptsprachen fordern natürlich immer IDispatch an und erledigen die Umwandlung von der ProgID in die CLSID automatisch. Der Computername kann sowohl der NetBIOS-Name des Rechners als auch der DNS-Name oder die IP-Adresse sein. Eine wichtige Fragestellung im Rahmen von DCOM ist stets, auf welchem Computer eine COM-Klasse instanziiert werden soll. Es gibt zwei Möglichkeiten, den Aktivierungsort zu spezifizieren: 왘 Über einen Eintrag in der Registrierungsdatenbank: In der Registrierungsdatenbank
Remote-
왘 Als expliziter Parameter beim Aufruf der Instanziierungsroutine innerhalb des COM-
Parameter
kann in einem AppID-Schlüssel RemoteServerName der DNS-Name des Rechners ein- ServerName getragen werden, auf dem die Instanziierung erfolgen soll. Clients: Die Angabe in der Registrierungsdatenbank ist ein Instrument, um Ortstrans- bei der Instanziieparenz herzustellen; ein COM-Client muss nicht wissen, wo sich das aufzurufende rung Objekt befindet. Dies ist in den Fällen von Nachteil, in denen der Client einen bestimmten Rechner ansprechen will. Der Client müsste dann vor der Instanziierung die Registrierungsdatenbank ändern. Dies birgt die Gefahr von Wechselwirkungen mit anderen Programmen, die ebenfalls dieses Objekt benutzen.
Viele Hochsprachen kapseln CoCreateInstance() hinter eigenen Funktionen: 왘 VBScript kapselt den Aufruf in CreateObject(). 왘 Visual Basic kapselt den Aufruf in new oder CreateObject(). 왘 JScript verwendet new ActiveXObject().
Dim Objektvariable set Objektvariable = CreateObject("Komponente.Klasse") Listing 7.7: Instanziierung einer COM-Klasse in allen Visual Basic-Dialekten
Dim Objektvariable As Komponente.Klasse set Objektvariable = new Komponente.Klasse Listing 7.8: Alternative Möglichkeit zur Instanziierung einer COM-Klasse in Visual Basic 6.0/VBA
var Objektvariable; Objektvariable = new ActiveXObject("Komponente.Klasse"); Listing 7.9: Instanziierung einer COM-Klasse in JScript
Dabei stehen jeweils weniger Optionen zur Verfügung als bei dem ursprünglichen CoCreate Instance(). Die verfügbaren Optionen reichen aber für die Scriptprogrammierung aus und verbergen viel von der Komplexität einer Instanziierung in COM.
113
7 Das Component Object Model (COM)
Ablauf
Aktivierungsvorgang Durch einen Aufruf von CoCreateInstance() führt der SCM folgende Schritte aus: 1. Der SCM sucht in der Registrierungsdatenbank nach einem entsprechenden Eintrag für die gewünschte CLSID. 2. Der SCM stellt fest, ob die Komponente auf dem lokalen System oder auf einem entfernten System instanziiert werden soll. Dabei hat ein bei CoCreateInstance() übergebener Rechnername das größte Gewicht. Fehlt dieser, prüft der SCM in der Registrierungsdatenbank, ob dort für die AppID, zu der die Klasse gehört, ein RemoteServer-Eintrag besteht. Fällt auch diese Überprüfung negativ aus, erfolgt die lokale Instanziierung. Sofern eine Fernaktivierung gewünscht ist, leitet der SCM die Anfrage über DCOM an den SCM des entfernten Systems weiter. 3. Der betroffene (lokale oder entfernte) SCM stellt fest, welche Datei die Komponente implementiert. Er lädt diese Datei und startet – wenn nötig – einen Prozess für die Komponente. 4. Jede COM-Komponente besitzt für jede Klasse eine so genannte Class Factory in Form eines ClassFactory-Objekts (auch ClassObject genannt) mit einer Standardschnittstelle IClassFactory. Einen Zeiger auf die Class Factory erhält der SCM über die DLLFunktion DllGetClassObject(), die von jeder COM-DLL bereitgestellt wird. Der SCM ruft die Methode IClassFactory::CreateInstance() auf. Die Class Factory erzeugt daraufhin eine neue Instanz der gewünschten COM-Klasse. 5. Das ClassFactory-Objekt übergibt dem SCM nach erfolgreicher Instanziierung einen Zeiger auf die gewünschte Schnittstelle des neuen Objekts. 6. Der SCM leitet diesen Schnittstellenzeiger an den Client weiter.
Rechner 1
Rechner 2
COM-Client
COM-Server Rückgabewert
Proxy
CoCreateInstance()
Rückgabewert
DCOM / RPC
Methodenaufruf
Methodenaufruf
Class Factory COM-Klasse
COM-Bibliothek (OLE32.DLL)
(CSLID, IID, [RemoteServer])
COM-Bibliothek (OLE32.DLL)
(Pointer)
(Pointer)
SCM (RPCSS.EXE)
(CLSID)
Registry
114
(RemoteServer)
Instanz der Klasse
Stub
Text
Bild 7.18: Ablauf der Aktivierung auf einem entfernten Rechner
(Pointer)
(Pointer)
DCOM / RPC (CLSID, IID)
(CLSID, IID)
(CLSID,IID)
SCM (RPCSS.EXE)
(LocalServer32/ InprocServer32)
(CLSID)
Registry
Objektaktivierung
Danach kann der Client ohne weitere Einschaltung des SCM direkt – über Proxy- und StubObjekte – mit der Komponente kommunizieren, da jede Schnittstelle IUnknown::QueryInterface() unterstützt und so zur weiteren Anfrage nach Schnittstellen verwendet werden kann. Surrogat-Prozesse Eine EXE-Datei wird entfernt aufgerufen, indem sie auf dem ent- Ausführung von DLLs in fernten Rechner gestartet wird. Dies ist mit DLLs nicht möglich. einem eige-
Damit eine prozessinterne Komponente von einem anderen Rechner aus aufgerufen wer- nen Prozess den kann, ist ein so genannter Surrogat-Prozess (engl. Surrogate Process) notwendig, der die prozessinterne Komponente aufnimmt und ausführt. Microsoft liefert zwei Standard-Surrogat-Prozesse: dllhost.exe und mts.exe. Dabei wird mts.exe nur innerhalb des Microsoft Transaction Server unter NT 4.0 verwendet. Unter COM+ ab Windows 2000 ist dllhost.exe der Standard-Surrogat-Prozess. dllhost.exe stand auch schon in NT 4.0 zur Verfügung, wenn eine Aufnahme in den MTS nicht gewünscht war. Sie konfigurieren eine Klasse einer In-process-Komponente für die Out-process-Verwendung, indem Sie die Klasse in ein MTS-Package (vgl. Kapitel 7.24) oder in eine COM+-Anwendung (vgl. Kapitel 7.25) integrieren. C++-Programmierer können einen solchen Surrogat-Prozess auch selbst schreiben. Komponenten, die auf Windows 9x/ME-Plattformen laufen, können nicht fernaktiviert werden. Diese Plattformen machen es lediglich möglich, eine Fernverbindung zu bereits laufenden Objekten herzustellen. COM-Server müssen also auf diesen Systemen manuell gestartet werden.
7.17.3
Windows 95/98/ME
Zugriff auf bestehende Instanzen
Die Basis für den Zugriff auf bestehende Instanzen ist der COM-Namensdienst. Mit diesem COMNamensdienst können einzelne Instanzen einer Klasse von anderen Instanzen unterschie- Namensdienst den werden. Moniker Instanzen haben in COM keine GUIDs, sondern Moniker (siehe Kapitel 7.4). Moniker werden intern selbst in Objekten (Moniker-Objekten mit der Schnittstelle IMoniker) gespeichert. Ein COM-Server kann einem COM-Client ein Moniker-Objekt übergeben, um es dem Client zu ermöglichen, zu einem späteren Zeitpunkt wieder eine Verbindung zu dieser Instanz aufzunehmen, nachdem die Objektreferenz zwischenzeitlich gelöscht wurde. Running Objects Table (ROT) Die Running Objects Table ist eine globale Tabelle auf ROT einem Rechnersystem, in der instanziierte Objekte verzeichnet werden können. Es gibt nur genau eine ROT pro Rechner. COM-Clients können Instanzen aus der ROT mitverwenden. So kann beispielsweise erreicht werden, dass neu zu öffnende Dateien einer Anwendung mit Multi-Document-Interface (MDI; z.B. Word 97) in einem bestehenden Fenster geöffnet werden können. Die Aufnahme einer Instanz in die ROT erfolgt keineswegs automatisch, sondern ist eine Option, die das Objekt selbst wahrnehmen oder eben nicht wahrnehmen kann. Ein Objekt meldet sich beim SCM über ein Moniker-Objekt an oder ab. Natürlich kann ein COM-Server die Entscheidung für oder gegen eine Anmeldung dem COM-Client überlassen. Die ROT kann mit Hilfe des in Visual Studio enthaltenen ROT-Viewers (siehe Kapitel 18 „Werkzeuge“) eingesehen werden.
115
7 Das Component Object Model (COM)
Als Scriptprogrammierer haben Sie ebenso wenig wie ein Visual Basic-Programmierer die Möglichkeit, Instanzen an die ROT zu melden. Zumindest scheint sich noch niemand die Arbeit gemacht zu haben, eine COM-Komponente zu schreiben, die die entsprechenden API-Aufrufe kapselt. File-Moniker
Aktivierung persistenter Instanzen aus Dateien Mit Hilfe von File-Monikern der folgenden Form besteht eine Zugriffsmöglichkeit auf im Dateisystem persistent gemachte Objektinstanzen. Dazu dient die COM-Bibliotheksfunktion CoGetInstanceFromFile(). file://pfad/dateiname.extension
Die Dokumente der Microsoft Office-Produktfamilie sind beispielsweise persistente Instanzen von COM-Klassen in Form von Compound Documents. CoGetInstanceFromFile()
Wenn ein Client mit Hilfe der COM-Bibliotheksfunktion CoGetInstanceFrom_File() (in Visual Basic und JScript: GetObject()) auf eine Datei zugreift, werden folgende Schritte vom SCM ausgeführt: 1. Anhand des Header der Datei bzw. der Dateierweiterung bestimmt der SCM die CLSID der COM-Klasse, die zur Verwaltung der angeforderten Datei fähig ist. Es ist auch möglich, bei CoGetInstanceFromFile() bzw. GetObject() eine CLSID (oder ProgID) für eine Klasse anzugeben, die zur Aktivierung verwendet werden soll. 2. Anschließend überprüft der SCM zunächst in der ROT, ob diese Objektinstanz bereits aktiviert wurde. Ist der zugehörige Moniker in der ROT eingetragen, so liefert der SCM den Schnittstellenzeiger an den Client. 3. War die Instanz nicht schon in Benutzung, so aktiviert der SCM eine neue Instanz der Klasse und fordert die Schnittstelle IPersistFile an. 4. Der SCM übergibt IPersistFile::Load() die Anforderung zum Laden der Datei und überlässt das weitere Vorgehen (also die Übernahme der Daten aus den Streams des Compound Documents in die internen Speicherstrukturen) der Objektinstanz der Klasse selbst. Dazu gehört auch der Eintrag in die ROT nach erfolgtem Laden der Datei.
Auslegungs- Moniker oder nicht Moniker Die Frage, ob irgendetwas als eine bestehende Instanz sache angesehen wird oder erst eine Instanz erzeugt werden muss, ist eine philosophische Frage,
die jeder Komponentenprogrammierer für sich selbst beantworten muss. Während viele Komponenten den Zugriff via Moniker ermöglichen, wird in anderen Fällen zunächst eine „leere“ Instanz einer Klasse erzeugt und diese dann per Methodenaufruf an eine Entität gebunden. Wie die folgende Tabelle zeigt, gibt es keine konsistente Sichtweise darauf, ob etwas direkt per Moniker angesprochen werden kann oder instanziiert werden muss.
116
Objektaktivierung
Instanz wird als persistent angesehen (Moniker-Zugriff via GetObject() )
Instanz muss erzeugt werden (Indirekter Zugriff via CreateObject() )
• • • •
• • • • •
Word-Datei Verzeichnisobjekt WMI-Objekt Registrierungsdatenbankschlüssel in der Komponente „ADsSecurity“
Access-Tabelle SQL-Server-Tabelle Ereignisprotokoll Klasse im COM+-Katalog Registrierungsdatenbankschlüssel in der Komponente „REGCOL“
Tabelle 7.6: Unterschiedliche Semantik hinsichtlich der Persistenz von Objekten in verschiedenen Komponenten
Teilweise gibt es auch für gleiche Entitäten der Realwelt zwischen verschiedenen Komponenten unterschiedliche Vorgehensweisen: So wird in der ADsSecurity-Komponente ein Registrierungsdatenbankschlüssel via Moniker angesprochen, in der Komponente REGCOL jedoch indirekt per Methodenaufruf.
7.17.4
Aktivierungsfehler
Es gibt eine Reihe möglicher Ursachen, warum eine Aktivierung fehlschlägt: 왘 Die Klasse ist gar nicht installiert.
Mögliche Fehlerquellen
왘 Die Klasse ist nicht richtig registriert. 왘 Die angegebene ProgID ist nicht mit der entsprechenden CLSID verbunden. 왘 Der Benutzer besitzt keine Rechte für die Nutzung der Klasse.
Bei einer Fernaktivierung kommen weitere Gründe hinzu: 왘 Der angesprochene Rechner existiert nicht oder ist nicht erreichbar. 왘 Auf dem angesprochenen Rechner ist DCOM deaktiviert. 왘 Für eine COM-DLL gibt es keinen Surrogat-Prozess. 왘 Die benötigten lokalen Registrierungsdatenbankeinträge sind nicht vorhanden.
Leider differenzieren viele Sprachen bzw. Hosts nicht genau zwischen all diesen Fehlerursachen. Mit Vorliebe melden sie einfach „Objekterstellung durch ActiveX-Komponente nicht möglich“ (VB 6.0) oder „ActiveX-Komponenten kann kein Objekt erstellen“ (WSH). Ganz abgesehen davon, dass die letzte Meldung grammatikalisch falsch ist, sind beides unglückliche Formulierungen, die einen Anfänger verwirren. Wieso will eine ActiveX-Komponente ein Objekt erstellen? Gemeint ist wohl, dass innerhalb einer Komponente eine bestimmte Klasse nicht instanziiert werden kann. Bild 7.19: Wenig aussagekräftige Fehlermeldung beim Windows Scripting Host
117
7 Das Component Object Model (COM)
7.18 COM-Anwendungen COM-Anwen- Eine COM-Anwendung fasst eine oder mehrere COM-Klassen zusammen und ermöglicht dungen die gemeinsame Konfiguration dieser Klassen. Zahlreiche Einstellungen (z.B. Sicherheits-
einstellungen) sind nur auf Anwendungsebene, nicht jedoch für eine einzelne Klasse konfigurierbar. Jede COM-Klasse kann nur einer COM-Anwendung angehören. Alle Einstellungen einer COM-Anwendung gelten für alle zugehörigen Klassen. AppIDs
Jede COM-Anwendung verfügt über eine so genannte Anwendungskennung, kurz AppID. AppIDs können mit einer CLSID identisch sein. Oft wird die erste CLSID einer Komponente auch als AppID benutzt. Eine COM-Anwendung ist nicht mit einer COM-Komponente gleichzusetzen. Eine COMAnwendung kann Klassen aus mehreren COM-Komponenten umfassen. Allerdings müssen alle COM-Klassen, die in einer COM-EXE enthalten sind, auch zur gleichen COMAnwendung gehören. Diese Beschränkung gilt nicht für COM-DLLs. COM-Objekte, die Instanzen von Klassen mit derselben AppID sind, werden im gleichen Prozess ausgeführt. Die AppIDs befinden sich in der Registrierungsdatenbank unter HKEY_LOCAL_ MACHINE\SOFTWARE\Classes\AppID\. Unterhalb einer AppID können die in der folgenden Tabelle genannten Einstellungen festgelegt werden.
Tabelle 7.7: Einstellungen für COMAnwendungen
Schlüssel
Erläuterung
AuthenticationLevel Individuelle Authentifizierungsstufe für diese COM-Anwendung RemoteServerName
Hier kann ein Rechner oder eine IP-Adresse des Computers eingegeben werden, auf die die COM-Klassen instanziiert werden sollen (DCOM). Dieser Wert wird vom Service Control Manager (SCM) ausgelesen, wenn der Client bei den Instanziierungsaufforderungen keinen expliziten Remote Server angegeben hat. Ist auch RemoteServerName nicht gesetzt, wird die Klasse vom SCM lokal installiert.
AccessPermission
Zugriffsrechte in Form einer ACL
RunAs
Identitätseinstellung
LaunchPermission
Startberechtigungen in Form einer ACL
Endpoints
Zu verwendende Protokolle und Portnummern bzw. Pfade
Globale Einstellungen
Ein Wertname ist in der Registrierungsdatenbank nur vorhanden, wenn ein Wert existiert. Ist ein Wert nicht belegt, gelten die unter HKEY_LOCAL_MACHINE\ SOFTWARE\Microsoft\Ole festgelegten Standardeinstellungen.
Tools
AppID-Konfiguration Kompliziert aufgebaute ACLs direkt in der Registrierungsdatenbank zu manipulieren, ist kaum möglich. Die einfachste Möglichkeit der Konfiguration von bestehenden COM-Anwendungen ist das DCOM Configuration Utility (DCOMCNFG, vgl. Kapitel 18 „Werkzeuge“). Auch der Microsoft COM Viewer bietet viele Einstellungsmöglichkeiten für COM-Anwendungen. Beim Anlegen neuer COM-Anwendungen bzw. der Änderung der zu einer Anwendung gehörenden Klassen lassen Sie obige Tools weitgehend im Stich: Sie können mit dem DCOMCNFG keine COM-Anwendungen erzeugen oder Klassenzuordnungen vornehmen.
118
COM-Assemblies
Mit dem COM Viewer können Sie nur COM-Anwendungen erzeugen, die aus genau einer Klasse bestehen. Es bleibt also nur der manuelle Eingriff in die Registrierungsdatenbank: Dazu nehmen Sie die CLSID einer der Klassen, die zur Anwendung gehören soll, und erzeugen einen neuen AppID-Schlüssel mit dem gleichen GUID. Danach tragen Sie diese AppID bei allen Klassen, die zur Anwendung gehören sollen, als AppIDWert in deren CLSID-Schlüssel ein.
DCOMCNFG ermöglicht auch eine Einstellung Konfigurationsberechtigungen, die Sie nicht als Unterschlüssel einer AppID finden werden. Diese Berechtigungen sind die Rechte auf den AppID-Schlüssel selbst, die sonst nur mit dem älteren RegEdt32-Registrierungsdatenbank-Editor eingesehen werden können.
Konfigurationsberechtigungen
7.19 COM-Assemblies COM hatte lange mit der DLL-Hölle zu kämpfen. Die DLL-Hölle entsteht im klassischen COM durch zwei Faktoren: 왘 Es kann nur eine Version einer bestimmten Komponente in der Registrierungsdaten-
bank registriert sein. Dies bezieht sich insbesondere auf Unter-Versionen (Patches). Natürlich kann eine COM-Komponente grundsätzlich in zwei verschiedenen Versionen auf einem System existieren, wenn die beiden Versionen verschiedene GUIDs verwenden und andere Dateinamen haben. Dann handelt es sich nämlich aus der Sicht von COM um zwei verschiedene Komponenten. Sobald aber von einer Komponente eine überarbeitete Version erscheint, die aus Kompatibilitätsgründen keine neuen GUIDs bekommen hat, kann nur eine der beiden Versionen auf dem System registriert sein. 왘 Eine Komponente, die in Benutzung ist, kann nicht aktualisiert werden. Beim Aus-
tausch der Komponentendatei (dll, exe etc.) kommt es zu einer Fehlermeldung. Komponenten sind teilweise auch noch lange nach ihrem tatsächlichen Nutzungsende vom System gesperrt. Side-by-Side-Execution (SxS) Grundsätzlich wurde ab Windows 2000 die DLL-Hölle SxS dadurch entschärft, dass nach DLLs zunächst im gleichen Verzeichnis gesucht wird, aus dem auch die EXE gestartet wurde. Allerdings funktionierte das Verfahren nicht mit COMKomponenten. Assemblies Ab Windows XP gibt es das neue Konzept der Assemblies, das es erlaubt, Windows XP mehrere verschiedene Versionen einer Komponente parallel auf einem System zu verwenden, und Windows Server 2003 auch wenn die Komponenten den gleichen Dateinamen und die gleichen GUIDs verwenden. Weil Assemblies diese ermöglichen, spricht Microsoft auch von Side-by-Side-Assemblies. Die Installation einer neuen Version einer Assembly beeinflusst die vorhandenen Anwendungen nicht mehr, so dass Anwendungen besser als bisher voneinander isoliert sind.
119
7 Das Component Object Model (COM)
Assembly Manifest
Eine Assembly ist eine feste Ansammlung einer oder mehrerer Komponentendateien. Wie die folgende Grafik veranschaulicht, unterscheidet sich das Konzept der COM-Assembly von dem Konzept der COM-Anwendung. Eine COM-Assembly muss nicht die gleichen Komponenten zusammenfassen wie eine COM-Anwendung. Die COM-Anwendung ist ein Instrument zur Zusammenfassung von Komponenten zu Prozessen und zur Konfiguration von Komponenten. Eine Assembly ist ein Instrument, um einen starken Zusammenhang zwischen verschiedenen Komponenten zu bilden, die sich gegenseitig nutzen. In vielen Fällen wird es aber sinnvoll sein, in COM-Anwendung und COM-Assembly die gleichen Komponenten zusammenzuschnüren.
Bild 7.20: COM-Anwendung vs. COMAssembly
Assembly
Assembly
COM-Anwendung = 1 Prozess Komponente
Komponente
Klasse
Klasse
Klasse
Klasse
Klasse
Klasse
Komponente
Komponente
Klasse
Klasse
Klasse
Klasse
Klasse
Klasse
Manifest
Manifest
(C)
[email protected] 2002
Manifeste Eine Assembly hat eine Konfigurationsdatei namens Assembly Manifest. Ein Assembly Manifest umfasst folgende Daten: 왘 Name der Assembly 왘 Jede Assembly hat eine viergliedrige Versionsnummer (a.b.c.d), z.B. 1.8.19.72. 왘 Die Typangabe win32
120
COM-Assemblies
왘 Liste der Komponentendateien, die zur Assembly gehören 왘 COM-Konfigurationsdaten, die COM für die Lokalisierung und Aktivierung dieser
Komponenten benötigt 왘 Liste der abhängigen Assemblies – jeweils mit Versionsnummer Das folgende Listing zeigt ein Beispiel für ein in Windows XP mitgeliefertes Manifest für die MFC-Bibliothek (Microsoft Foundation Classes – die Laufzeitumgebung für Visual C++) in der Version 6.0. Die Assembly umfasst die Dateien mfc42.dll, atl.dll und mfc42u.dll. Listing 7.10: Beispiel für ein Manifest
121
7 Das Component Object Model (COM)
Application Manifest
Anwendungen Eine Anwendung ist ein COM-Client, der eine oder mehrere Assemblies verwendet. Eine Anwendung besitzt im neuen Konzept ebenfalls eine XML-Datei, die Application Manifest heißt. Ein Application Manifest umfasst folgende Daten: 왘 Name der Anwendung 왘 Eine viergliedrige Versionsnummer 왘 Liste der abhängigen Assemblies – jeweils mit Versionsnummer
Global Side- Finden einer Komponente Die Versionsnummer und Abhängigkeitsdaten sind die By-Side-Store zentrale Neuerung. COM sucht für den Client eine Komponente, die die angegebenen Bedin-
gungen erfüllt. Gesucht wird im Pfad der Anwendung und in einem globalen Komponentenverzeichnis mit dem Namen Global Side-By-Side-Store (WinSXS). Der Global Side-By-SideStore liegt unter \Windows\WinSXS. Dieses Verzeichnis gab es vor Windows XP nicht.
Bild 7.21: Verzeichnis WinSXS unter Windows XP
Das Assembly-Konzept erfordert keine Änderung an der Implementierung der Komponente selbst. Es ist lediglich das Erstellen von Manifesten erforderlich. So kann eine Anwendung auch zu einem späteren Zeitpunkt durch einen Administrator umkonfiguriert werden, so dass die Anwendung andere Versionen bestimmter Komponenten verwendet. Name Eine Assembly soll einen hierarchischen Namen besitzen in der Form Firmenname.Anwendungsname.Anwendungsteil.Komponentenname
Ein Beispiel dafür ist PearsonEducation.AddisonWesley.BuecherVerwaltung.Buch
Assembly-Typen COM (ab Windows XP) unterscheidet zwei Typen von Assemblies: Private Assemblies
122
왘 Private Assemblies, die nur von einer einzigen Anwendung verwendet werden und die im
Verzeichnis bzw. einem Unterverzeichnis der Anwendung gespeichert sind. Sie werden anhand ihres Dateinamens identifiziert und können einfach über das Kopieren per Dateisystem installiert werden. Microsoft spricht in diesem Zusammenhang von XCopyDeployment.
COM-Kategorien
왘 Eine Shared Assembly kann – wie jede COM-Komponente bisher – von mehreren Anwen-
Shared
dungen genutzt werden. Sie müssen digital signiert werden und im Global Side-By-Side- Assemblies Store (WinSXS) liegen. Shared Assemblies müssen mit Windows Installer 2.0 oder höher installiert werden. Im WinSXS gibt es für jede Assembly ein Manifest im Unterverzeichnis /Manifests und ein Unterverzeichnis, das den Namen der Assembly zusammen mit dem öffentlichen Schlüssel trägt (z. B. x86_Microsoft.Tools.Visual CPlusPlus.Runtime-Libraries_ 6595b64144ccf1df_6.0.0.0_x-ww_ff9986d7). In diesem Verzeichnis werden die Komponentendateien dieser Assembly gespeichert. So sind die einzelnen Assemblies voneinander isoliert und gleichnamige Dateien stellen kein Problem mehr dar.
COM und .NET Assemblies und Manifeste in COM sind ähnlich, aber nicht gleich den Assemblies und Manifesten im .NET Framework. So heißt zum Beispiel der Global Side-By-Side-Store im .NET Framework Global Assembly Cache (GAC). Der Aufbau der XML-Dateien ist anders.
7.20 COM-Kategorien COM-Kategorien stellen eine Möglichkeit dar, COM-Klassen zu kategorisieren. Die Kate- Komponengorisierung dient dazu, leichter feststellen zu können, ob ein COM-Client und ein COM- tenkategorien Server zusammenpassen. Obwohl es Klassen betrifft, die kategorisiert werden, heißt diese Funktion Komponentenkategorien (Component Categories) – ein typischer Fall von großem MINFU (vgl. Vorwort). Ein Client, der eine bestimmte Schnittstelle benötigt, aber keine COM-Klasse kennt, die diese implementiert, müsste normalerweise jede Klasse instanziieren und mit Hilfe von QueryInterface() anfragen, ob die betreffende Schnittstelle implementiert wird. Sofern der Client nicht nur eine einzelne Schnittstelle, sondern einen Satz von Schnittstellen benötigt, müsste er QueryInterface() bei jeder Klasse entsprechend oft aufrufen. Durch die Zuordnung einer COM-Klasse zu einer Kategorie kann in der Registrierungsdatenbank hinterlegt werden, dass eine COM-Klasse einen bestimmten Satz von Schnittstellen implementiert. Ein Client muss dann lediglich in der Registrierungsdatenbank nach der entsprechenden Kategorie suchen. Weitere Informationen finden Sie in der MSDN Library [MSD01c]. Benötigte und implementierte Kategorien Eine COM-Klasse kann zu beliebig vielen Kategorien gehören; diese Zuordnung wird Implemented Categories genannt. Eine Komponente kann aber auch selbst mit Hilfe von Required Categories fordern, dass ein COM-Client zu einer bestimmten Komponentenkategorie gehört. Dies ist eine wichtige Funktion, wenn COM-Server Funktionen innerhalb eines COM-Clients aufrufen sollen.
Required Categories und Implemented Categories
Jede Komponentenkategorie besitzt einen GUID, CategoryID (CATID) genannt. Eine Liste der definierten COM-Kategorien befindet sich in der Registrierungsdatenbank unter dem Schlüssel HKEY_CLASSES_ROOT\Component Categories. Einsatzgebiete COM-Kategorien können eingesetzt werden, wenn Clients nicht auf Einsatzeine bestimmte COM-Klasse festgelegt sind, sondern jede COM-Klasse akzeptieren wür- gebiete den, die eine bestimmte Funktionalität erbringt. Damit ließe sich ein einfacher Trader für
123
7 Das Component Object Model (COM)
COM-Komponenten realisieren (vgl. [NNI00]). Leider werden COM-Kategorien so heute noch nicht benutzt. Sie werden bislang nur verwendet, um eine grobe Einteilung in verschiedene Komponentenarten herzustellen. Entwicklungsumgebungen, die eine Liste von verfügbaren Komponenten anbieten, haben auf diese Weise einen schnellen Zugriff auf die Komponenten eines Typs. Denn es sollten in einem Dialogfenster, das die verfügbaren ActiveXSteuerelemente zeigt, keine nichtvisuellen COM-Komponenten angezeigt werden. Standardkategorien
Im Standard installierte Komponentenkategorien auf einem Windows-System sind beispielsweise: 왘 Controls 왘 Controls that are safely scriptable („Steuerelemente, die sicher für das Scripting sind“) 왘 Document Objects 왘 Embeddable Objects 왘 Java Classes 왘 Active Scripting Engines 왘 Automation Objects
Persistenz
Tabelle 7.8: Komponentenkategorien für Objektpersistenz in COM
Durch Komponentenkategorien kann auch beschrieben werden, welchen Mechanismus eine Klasse verwendet, um Objekte persistent zu machen (siehe Tabelle). Ein Objektcontainer (z.B. ein Webbrowser oder ein Windows-Fenster) sollte eine Klasse, die einen Persistenzmechanismus verlangt, der von dem Container und seiner Umgebung nicht unterstützt wird, nicht erzeugen. Name der Kategorie
CATID
RequiresDataPathHost
0de86a50-2baa-11cf-a229-00aa003d7352
PersistsToMoniker
0de86a51-2baa-11cf-a229-00aa003d7352
PersistsToStorage
0de86a52-2baa-11cf-a229-00aa003d7352
PersistsToStreamInit
0de86a53-2baa-11cf-a229-00aa003d7352
PersistsToStream
0de86a54-2baa-11cf-a229-00aa003d7352
PersistsToMemory
0de86a55-2baa-11cf-a229-00aa003d7352
PersistsToFile
0de86a56-2baa-11cf-a229-00aa003d7352
PersistsToPropertyBag
0de86a57-2baa-11cf-a229-00aa003d7352
Als Scriptentwickler sollten Sie sich besonders die verschiedenen, mit dem Begriff Active Scripting beginnenden Komponentenkategorien anschauen. Dort können Sie die installierten Scripting Engines entnehmen! Weiterhin ist natürlich die Liste der Automation Objects interessant. Benutzen Sie zur Betrachtung den Microsoft COM Viewer.
7.21 Persistenz und Structured Storage Compound Files
124
Unter dem Begriff Structured Storage bietet COM ein Verfahren an, um Objekte und Objektmengen in strukturierter Form in Dateien zu speichern (Objektpersistenz). Die Persistenz erfolgt jedoch nicht automatisch oder durch eine einfache Deklaration. Sowohl der Programmierer des COM-Servers als auch der Programmierer des COM-Clients müssen
Persistenz und Structured Storage
die Persistenz explizit programmieren. Structured Storage definiert eine Reihe von Standardschnittstellen und damit Regeln, wie die Speicherung erfolgen kann. Ein so genanntes Compound File ist eine Datei, die eine Sammlung von Storages und Streams enthält. Ein Compound File besteht aus einem Storage, der beliebig viele Sub-Storages enthalten kann. Jedes Storage kann aus Streams und weiteren Sub-Storages bestehen. Ein Compound File ist daher vergleichbar mit einem Dateisystem: Storages sind Verzeichnisse, Streams sind Dateien. Der große Vorteil von Structured Storage besteht in der Möglichkeit, unterschiedliche PersistenzArten von Daten in einer Datei zu speichern und einzelne Teile zu ändern, ohne das gesamte schnittstellen Compound File ändern zu müssen. COM definiert für Structured Storage die Standardschnittstellen IPersist, IStorage, IStream und IRootStorage und liefert Standardimplementierungen im Rahmen der COM-Bibliothek. Viele Windows-Anwendungen (z.B. Word-Dateien (.doc) ab Version 6.0, Data Transforma- Anwention Service-Dateien (.dts)) speichern ihre Daten in Compound Files. Die Structured Sto- dungsgebiete rage-Technologie ist auch die Basis für die Speicherung von Zusatzattributen zu Dateien (z.B. Autorenname, Firmenname, Kategorien, Versionsnummer). Bild 7.22: Eine durch Structured Storage gegliederte Datei
Compound File Storage
Storage
Stream
Storage
Stream
Storage
Stream
Storage
Storage
Stream
Storage
Stream
Stream
Storage
Storage
Stream
Stream
Structured Storage ist nicht zu verwechseln mit NTFS-Streams. Compound Files können auch im FAT-Dateisystem gespeichert werden. Ein Stream kann auch die CLSID der COM-Klasse enthalten, mit der die Datei geöffnet Dateitypen werden soll. In diesem Fall öffnet Windows eine Word-Datei auch dann mit Microsoft Word, wenn diese keine oder eine andere Dateierweiterung als .doc hat. Windows schaut bei einer Datei, die einen Stream mit einer CLSID besitzt, gar nicht in der Registrierungsdatenbank nach der Dateierweiterung nach.
125
7 Das Component Object Model (COM)
7.22 COM-Sicherheit Sicherheitsfunktionen
COM benutzt für die Realisierung von Sicherheitsfunktionen die RPC-Sicherheitsinfrastruktur. Diese basiert auf den so genannten Security Support Providern (SSP). Ein SSP ist in Form einer DLL installiert. NT 4.0 unterstützt standardmäßig nur den NT LAN-Manager Security Support Provider (NTLMSSP), implementiert in secur32.dll. Ab Windows 2000 wird zusätzlich Kerberos unterstützt. Kerberos ist allerdings nur für entfernte, nicht für lokale Aufrufe verfügbar. Die Installation zusätzlicher SSPs ist jeweils möglich. Weitere Informationen zur COM-Sicherheit finden Sie in der MSDN Library [MSD01a]. Das DCOM Configuration Utility (DCOMCNFG) ermöglicht eine einfachere und komfortablere Anzeige und Einstellung der Sicherheitsinformationen, als dies über eine direkte Manipulation der Registrierungsdatenbank möglich wäre).
Konfigura- Im Rahmen der COM-Sicherheit sind folgende Punkte konfigurierbar: tion der COM-Sicher- 왘 Die Authentifizierungsstufe legt fest, wie stark die Kommunikation zwischen COM-Client heit und COM-Server gesichert wird. Die Authentifizierungsstufe umfasst in COM nicht nur
die Authentifizierung, sondern auch den Schutz der Integrität und Vertraulichkeit. 왘 Die Identität einer Klasse bestimmt, unter welchem Benutzerkontext („Principal“) die
Instanzen einer Klasse agieren. Mit einem Benutzerkontext ist eine bestimmte Menge von Benutzerrechten verbunden. Ein COM-Objekt kann alle Aktionen ausführen, die den Benutzerrechten des Principal entsprechen. 왘 Die Impersonifizierungsstufe legt fest, inwiefern die Benutzerrechte des COM-Clients auf den COM-Server übertragen werden können. 왘 Im Rahmen der Zugriffskontrolle ist konfigurierbar, wer eine COM-Klasse aktivieren, nutzen oder konfigurieren kann. All diese Einstellungen werden auf der Ebene einer COM-Anwendung konfiguriert und gelten damit für alle zu der COM-Anwendung gehörenden Klassen. Die Einstellungen können nicht direkt auf Klassenebene vorgenommen werden. Mit Ausnahme der Identität können die Sicherheitseinstellungen auch global vorgegeben werden. Diese Standardeinstellungen gelten für alle nicht näher konfigurierten Komponenten. Die Standardeinstellungen liegen in der Registrierungsdatenbank unter HKEY_LOCAL_ MACHINE\SOFTWARE\Microsoft\Ole\. Programmatische Sicherheit
126
Neben der deklarativen Sicherheit, also der Vorkonfiguration der Sicherheitseinstellungen, unterstützt COM auch programmatische Sicherheit, also das Lesen und Ändern von Sicherheitseinstellungen zur Laufzeit eines Programms. Diese Möglichkeit wird jedoch nur von wenigen Komponenten genutzt. Einen kompletten Zugriff auf die DCOMSicherheit bietet derzeit nur die WMI-Komponente.
COM-Sicherheit
7.22.1
Authentifizierung
Die folgende Tabelle zeigt die verfügbaren Authentifizierungsstufen. Name
Bedeutung
Wert
Default (Standard)
Es wird die gegenwärtige Verbindungsauthentifizierung verwendet.
0
None (kein)
Keine Authentifizierung
1
Connect (Verbinden)
Authentifizierung beim ersten Methodenaufruf, später kein Austausch mehr. Ein Angriff durch Nachrichtenwiederholung ist möglich.
2
Call (Aufruf)
Authentifizierung bei jedem RPC
3
Packet (Paket)
Zusätzlich: Verschlüsselung jedes einzelnen Netzwerkpakets (verbesserter Schutz gegen Nachrichtenwiederholung)
4
Packet Integrity (Paketintegrität)
Zusätzlich: Prüfsumme über Paketinhalt schützt vor Verfälschung der Nachrichten
5
Privacy Zusätzlich: Verschlüsselung des Paketinhalts (schützt (Paketvertraulichkeit) Vertraulichkeit)
Tabelle 7.9: COM-Authentifizierungsstufen
6
Die Stufen Packet Integrity und Privacy bieten zwar deutlich mehr Sicherheit, führen aber zu einer Verschlechterung der Performance und einer Erhöhung der Netzwerklast, da jedes übertragene Byte von dem Security Support Provider (SSP) verarbeitet werden muss.
7.22.2
Identität
Für jede einzelne COM-Anwendung kann in dem zugehörigen AppID-Schlüssel im Unter- Identitätsschlüssel RunAs spezifiziert werden, unter welchem Benutzerkontext die COM-Anwendung einstellungen ausgeführt werden soll. Für die Identität gibt es drei Möglichkeiten: 왘 Interaktiver Benutzer: Interaktiver Benutzer ist der Benutzer, der sich gerade an dem
jeweiligen System angemeldet hat. Für den Client ist also nicht determinierbar, unter welchem Benutzer die Komponente ausgeführt wird. RunAs muss auf „Interactive User“ gesetzt werden. Wenn sich kein Benutzer angemeldet hat, kann die Komponente nicht ausgeführt werden. 왘 Benutzer, der die Anwendung startet: Dies ist die Standardeinstellung (RunAs ist nicht gesetzt). Das COM-Objekt benutzt während der Ausführung den Benutzerkontext, unter dem auch der aufrufende Client ausgeführt wird. Für jeden Benutzer, der sich mit einer COM-Anwendung verbindet, muss Windows NT eine neue Interactive WindowSession eröffnen. 왘 Dezidierter Benutzer: Das COM-Objekt wird unter einem bestimmten Benutzerkonto ausgeführt, unabhängig davon, wer das Objekt nutzt. Eine Sonderform gibt es für Windows-Dienste, die auch unter dem Systemkonto laufen dürfen.
127
7 Das Component Object Model (COM)
Auch in diesem Fall wird für jeden Benutzer eine interaktive Window-Session benötigt. Allerdings ist hier die Anzahl der nötigen Window-Sessions auf dem COM-Server bestimmbar und unabhängig von der Anzahl der aufrufenden Clients. Diese Einstellung ermöglicht es auch, Zugriffsrechte zu kapseln. Indem die Komponente durch Zuweisung eines entsprechenden dezidierten Benutzerkontos mehr Rechte erhält, kann ein Benutzer über wohldefinierte Schnittstellen einzelne Aktionen ausführen, die über seine eigenen Rechte hinausgehen. Bild 7.23: Identitätseinstellung in DCOMCNFG für die WMIKomponente
Einem Benutzerkonto, das als dezidiertes Benutzerkonto für COM-Anwendungen verwendet wird, muss im Benutzermanager bzw. in den Windows-Sicherheitsrichtlinien das Recht Anmelden als Stapelverarbeitungsauftrag zugewiesen werden.
7.22.3 Benutzerkontextwechsel
Impersonifizierung
Die Impersonifizierungsstufe bestimmt, inwiefern ein Objekt Informationen über den Aufrufer erhält und inwiefern es unter dessen Benutzerrechten agieren kann. Impersonifizierung (engl. Impersonation) bezeichnet die Fähigkeit einer Softwareroutine, den Benutzerkontext, unter dem sie agiert, zu wechseln. Einige Autoren benutzen statt des Kunstworts „Impersonifikation“ auch die Begriffe „Imitation“ oder „Identitätswechsel“. Die nachfolgende Tabelle zeigt die möglichen Impersonifizierungsstufen. Standard ist die Stufe Identify. Delegate wird erst ab Windows 2000 unterstützt, sofern Kerberos als SSP verwendet wird. Das Problem mit diesem Modus ist, dass die Rechte über eine endlose Kette weitergegeben werden können, so dass Aktionen, die unter dem Recht des Benutzers aufgerufen werden, kaum mehr kontrollierbar sind.
128
COM-Sicherheit
Rechte
Benutzer
"Objekt"
Bild 7.24: Impersonifizierung
Rechte Rechte Rechte Komponente
Rechte
Komponente Rechte Komponente
Benutzer
Benutzer Benutzer
(C)
[email protected] 2002
Name
Bedeutung
Wert
Anonymous
Das COM-Objekt hat keinen Zugriff auf die Anmeldedaten des Aufrufers. Es hat keine Möglichkeit, in Erfahrung zu bringen, wer das Objekt aufgerufen hat.
1
Identify
Das COM-Objekt kann die Anmeldedaten abfragen.
2
Impersonate Das COM-Objekt kann die Anmeldedaten ermitteln und auf Betriebssystemebene Operationen unter Verwendung des Benutzerkontextes des Aufrufers ausführen.
3
Delegate
4
Das COM-Objekt kann auf alle Ressourcen unter Verwendung des Benutzerkontextes des Aufrufers zugreifen.
Tabelle 7.10: Impersonifizierungsstufen
Eine Aufrufkette kann beliebig lang werden, da COM-Klassen wiederum COM-Klassen aufrufen können.
7.22.4
Zugriffsberechtigungen
Im Rahmen der Zugriffskontrolle ist konfigurierbar, wer die zu einer COM-Anwendung gehörenden COM-Klassen aktivieren, nutzen oder konfigurieren kann. COM unterscheidet folgende Sicherheitseinstellungen zu einer COM-Anwendung: 왘 Die Startberechtigungen legen fest, wer Instanzen der Klassen einer COM-Anwendung
erzeugen darf. Mögliche Rechte sind Starten zulassen und Starten verweigern.
Startberechtigungen
129
7 Das Component Object Model (COM)
Zugriffs- 왘 Die Zugriffsberechtigungen bestimmen, wer auf die laufenden Instanzen der Klassen berechtieiner COM-Anwendung zugreifen darf. Mögliche Rechte sind Zugriff erlauben und gungen
Zugriff verweigern.
Konfigura- 왘 Die Konfigurationsberechtigungen regeln, wer die Sicherheitseinstellungen einer COMtionsberechAnwendung verändern darf. Mögliche Rechte sind Lesen und Uneingeschränkter Zugriff. tigungen
Start- und Zugriffsberechtigungen werden für jede COM-Anwendung in der Registrierungsdatenbank unterhalb ihres AppID-Eintrags in Form von drei Access Control Lists (ACLs) abgespeichert. Die Konfigurationsberechtigungen entsprechen der ACL des AppID-Eintrags in der Registrierungsdatenbank selbst. Diese Zugriffsrechte sind über die erweiterten Sicherheitseinstellungen RegEdt32 in feinerer Granularität konfigurierbar als über DCOMCNFG, das nur die Stufen Lesen und Uneingeschränkter Zugriff (in RegEdt32 Vollzugriff genannt) zulässt. Zugriffsrechte auf Schnittstellen- und Methodenebene Programmgesteuert können die Zugriffsrechte auch auf Schnittstellenebene geprüft werden. Dazu dienen die Standardschnittstellen IClientSecurity und IServerSecurity. In COM+ ab Windows 2000 ist die Konfiguration von Zugriffsrechten auf Methodenebene möglich. Bild 7.25: Sicherheitseinstellungen in DCOMCNFG
Windows 9x/ME
130
Sicherheit unter Windows 95/98/ME Unter Windows 95/98/ME gibt es keine COMSicherheit bei der Nutzung lokaler Komponenten. Die Sicherheitsfunktionen greifen nur für die Fernnutzung und auch nur dann, wenn sich das Betriebssystem im Sicherheitsmodus „Zugriffskontrolle auf Benutzerebene“ befindet. Die Zugriffskontrolle auf Ressourcenebene wird nicht unterstützt. Sofern die Zugriffskontrolle auf Ressourcenebene eingestellt ist, besteht nur die Möglichkeit, die Fernaktivierung von Komponenten grundsätzlich zu erlauben oder zu verbieten. Auch im Modus „Zugriffskontrolle auf Benutzerebene“ sind nur die Standardzugriffsberechtigungen konfigurierbar. Die Authentifizierungsunterstützung in Windows 95/98/ME ist eingeschränkt, da eingehende Aufrufe höchstens bis zur Stufe „Connect“ entgegengenommen werden können. Aufrufe mit einer höheren Stufe werden abgewiesen. Weitere Informationen dazu finden Sie im COM Security FAQ [Q158508].
Active Scripting
7.23 Active Scripting Das Grundkonzept des Active Scripting wurde bereits im Einführungskapitel erläutert. Die folgende Grafik stellt eine detaillierte Erläuterung des Zusammenhangs zwischen Scripts und COM-Komponenten dar. Die COM-Komponenten, die für Active Scripting verwendet werden sollen, müssen COM-Automation (IDispatch-Schnittstelle) unterstützen. COMKomponenten, die nur IUnknown anbieten, können nicht verwendet werden. Active Scripting Host
Active Scripting Engine 1
Unterroutine 1
Active Script Quellcode
Bild 7.26: Die Active ScriptingArchitektur
Unterroutine 2 Unterroutine 3
Active Scripting Engine 2 Unterroutine 1
Active Script Maschinencode
Unterroutine 2 Unterroutine 3
Active Scripting Engine 3
nicht möglich!
IDispatch
IDispatch
COM-Klasse
COM-Klasse
COM-Komponente 1
IDispatch
IUnknown
COM-Klasse
COM-Klasse
COM-Komponente 2 (C) Holger Schwichtenberg 2001
Auch Active Scripting Hosts und Active Scripting Engines sind COM-Komponenten, die spezielle Schnittstellen implementieren.
7.23.1
Entwicklung von Scripting Engines
Die Implementierung einer Scriptsprache ist dann kompatibel mit der Active Scripting- IActiveScriptParse Architektur, wenn folgende Voraussetzungen erfüllt sind: 왘 Die Sprache ist in Form einer COM-Klasse implementiert. 왘 Die COM-Klasse unterstützt die COM-Schnittstellen IActiveScript, IActiveScript
Parse.
131
7 Das Component Object Model (COM)
Mit Sprachen, die COM-Komponenten mit Mehrfachschnittstellen implementieren können, kann man eigene Active Scripting Engines erstellen. Dies ist jedoch nicht Thema dieses Buchs.
7.23.2 Ansicht der installierten Scriptsprachen
Installierte Scripting Engines
Scriptsprachen werden bei der Installation in der Registrierungsdatenbank unter einer speziellen Kategorie von Komponenten registriert. Am einfachsten kann man die auf einem System installierten Scriptsprachen mit Hilfe des Tools COM Viewer (siehe Kapitel 18 „Werkzeuge“) einsehen. Dort existieren mehrere Einträge unter Active Scripting Engine, die die Sprachen nach ihren Fähigkeiten kategorisieren.
Bild 7.27: Anzeige der installierten Scriptsprachen im COM Object Viewer
Bild 7.28: VBScriptProgID in der Registrierungsdatenbank
ProgID der Sprache
132
Zu jeder Sprache werden Sie einen Eintrag ProgID finden. Diese ProgID (Programmatic Identifier) ist in einigen Scripting Hosts wichtig zur Identifizierung der Scriptsprache. Visual Basic Script hat die ProgID VBScript und die Sprache JScript die ProgID JScript. Über einen Registrierungsdatenbankschlüssel der Form HKEY_CLASSES_ROOT\ProgID wird der Zusammenhang zwischen der Sprache und der Binärdatei hergestellt, die die Sprache implementiert.
Active Scripting
7.23.3
Entwicklung von Scripting Hosts
Ein Active Scripting Host in eine COM-Klasse, die die Schnittstelle IActiveScriptSite implementiert. Eine einfachere Möglichkeit ist die Verwendung des Microsoft Script Control (vgl. Kapitel 19 „Fortgeschrittene Active Scripting-Techniken“).
7.23.4
COM-Komponenten beim Active Scripting
Die Active Scripting-Architektur ermöglicht es allen Active Scripting-Sprachen, auf alle Nur COMCOM-Komponenten zuzugreifen, die COM-Automation unterstützen. COM-Klassen, die Automation keine IDispatch-Schnittstelle haben, können nicht genutzt werden. Zwar unterstützen viele COM-Komponenten COM-Automation, jedoch gibt es Komponenten, die den Dienst nicht anbieten und daher im Windows Scripting nicht verwendbar sind. Auf einen Zugriff auf Nicht-COM-APIs (z.B. DLLs, die keine COM-Komponenten sind) hat Microsoft ausdrücklich verzichtet. Es gibt jedoch inzwischen Ansätze, dies zu ermöglichen (DynaWrap, siehe [BOR00]).
7.23.5
Eingebaute Objekte
Viele Scripting Hosts besitzen so genannte Intrinsic Objects (auch Built-In Objects oder Eingebaute Internal Objects) für den Zugriff auf den Scripting Host und dessen direkte Umgebung. Ein- Objekte gebaute Objekte sind COM-Objekte, die beim Start des Scripting Host oder beim Start eines konkreten Script automatisch durch den Scripting Host instanziiert werden. Dem Script steht die so erzeugte Instanz in Form eines bestimmten Bezeichners als Eingebautes Objekt zur Verfügung. 왘 Die Active Server Pages (ASP) stellen eine Reihe von Eingebauten Objekten zur Kommu-
nikation mit dem Webserver zur Verfügung (z.B. Request, Response, Server). 왘 Der Windows Scripting Host (WSH) liefert ein WScript-Objekt zum Zugriff auf den Host und Informationen über das aufgerufene Script. 왘 Der Exchange Event Agent bekommt über das Objekt EventDetails Zugriff auf die E-Mail, die seinen Aufruf getriggert hat, und auf das Verzeichnis, in dem die Nachricht steht. 왘 Ein Transformation Script im Data Transformation Service (DTS) hat über die Objekte DTSSource und DTSDestination die nötigen Informationen über die an der Transformation beteiligten Daten.
Beispiele für Eingebaute Objekte in verschiedenen Scripting Hosts
Jeder Scripting Host hat andere Eingebaute Objekte. Oft stehen die dazugehörigen Klassen nur diesem Scripting Host zur Verfügung, so dass eine Instanziierung durch andere Scripting Hosts oder Anwendungen unmöglich ist. Es kann aber natürlich auch vorkommen, dass eine Klasse, welche in einem Scripting Host ein Eingebautes Objekt ist, in einem anderen Scripting Host durch explizite Instanziierung erzeugt wird.
133
7 Das Component Object Model (COM)
7.24 Microsoft Transaction Server (MTS) MTS
Den Microsoft Transaction Server (MTS), früherer Codename Viper, hätte man besser Microsoft Component Server nennen sollen, denn den wesentlichen Mehrwert bietet er in der Bereitstellung einer Umgebung für COM-Komponenten und erst in zweiter Linie für die Transaktionsverarbeitung. Marketingtechnisch war der Name MTS aber sicherlich erste Wahl, denn Microsoft wollte das imageträchtige Feld der Transaktionsverarbeitung mit einem eigenen Produkt besetzen. Der MTS Version 2.0 kann unter NT 4.0 im Rahmen des Option Packs installiert werden. Unter Windows 95/98/ME erhalten Sie den MTS durch Installation des Personal Webserver. Ab Windows 2000 ist die MTS-Funktionalität ein Teil von COM+ und damit fest im Betriebssystem verankert. Zur Verwendung der MTS-Funktionalität ab Windows 2000 beachten Sie bitte auch die Ausführungen zu COM+ im nächsten Kapitel, da sich einige Aspekte des MTS ab Windows 2000 geändert haben.
DNA
Microsofts Distributed InterNet Applications Architecture (DNA) sieht eine moderne Unterteilung in Präsentationsschicht, Anwendungsschicht und Datenzugriffsschicht vor. Diese Architektur heißt auch Three-Tier-Architecture, die Anwendungsschicht, auf der der MTS zuhause ist, wird auch Middle-Tier genannt. Die Anwendungsschicht beherbergt Geschäftsobjekte, die die von der Präsentationsschicht kommenden Benutzereingaben verarbeiten. Dabei sind in der Regel Zugriffe auf Datenbanken über die Datenzugriffsschicht notwendig. Die Transaktionssteuerungsfunktion des MTS soll hier nicht thematisiert werden, da dies vor allem die Programmierung von eigenen COM-Servern betrifft. Zum Thema Transaktionsprogrammierung mit dem MTS sei auf [SCH00a] verwiesen. Der MTS wird hier aus drei Gründen behandelt: 왘 Der MTS übernimmt für COM-DLLs die Funktion eines Surrogat-Prozesses, was die Mög-
lichkeit eröffnet, COM-DLLs als Out-process- oder Remote-Komponenten zu nutzen. 왘 Mit Hilfe des MTS sind erweiterte, rollenbasierte Sicherheitseinstellungen für Komponenten möglich. 왘 Der MTS kann per Programmcode administriert werden.
7.24.1 MTS Explorer
MTS-Administration
Die Administration des MTS erfolgt unter NT 4.0 über ein Snap-In für die Microsoft Management Console (MMC) mit dem Namen Transaction Server Explorer. Den MTS Explorer gibt es auch als Stand-alone-Anwendung (mtxexp.exe) für Windows 95/98/ME – allerdings mit anderer Oberfläche und eingeschränkten Möglichkeiten. Der MTS-Explorer wird im Kapitel 18 „Werkzeuge“ behandelt.
134
Microsoft Transaction Server (MTS)
7.24.2
Interception
Der MTS arbeitet nach dem Interception-Prinzip: COM-Client und COM-Server kommuni- Interception zieren nicht direkt, sondern über ein Interceptor-Objekt miteinander. Das Interceptor-Objekt ist wie ein Mantel um ein COM-Objekt gelegt, der die Methodenaufrufe des COM-Clients entgegennimmt und an das angesprochene COM-Objekt weiterleitet. Interception wird auch Objektkontext genannt, das Interceptor-Objekt heißt auch Kontextobjekt oder Context-Wrapper-Objekt. Interception erfolgt auf Klassenebene, nicht auf Komponentenebene. Der MTS fügt dazu zwischen den Server-Stub und die Klasse ein Context-Wrapper-Objekt ein, mtx.exe wobei dies deutliche Spuren in der Registrierungsdatenbank hinterlässt: Der LocalServer32Eintrag unterhalb der CLSIDs der Klassen weist nicht mehr auf die DLL, sondern auf einen Eintrag der Form C:\WINDOWS\ SYSTEM\mtx.exe /p:{8FBA079C-B9A4-11D2-978B0008C73ADEC0}. Hinter mtx.exe verbirgt sich der Context-Wrapper, der gleichzeitig ein Surrogat-Prozess ist. Der MTS startet pro Package eine Instanz von mtx.exe; alle Objekte eines Package laufen also im gleichen Prozess. Neben den bereits erwähnten Transaktionsdiensten, dem Surrogat-Prozess und den erwei- Zusätzliche terten, rollenbasierten Sicherheitseinstellungen bietet der MTS auf Basis der Interception Dienste auch noch folgende Dienste an: 왘 Connection Pooling für Datenbankverbindungen: Wenn ein MTS-Objekt eine Daten-
bankverbindung verwirft, wird diese durch den Objektkontext nicht wirklich geschlossen, sondern für die weitere Verwendung vorgehalten. 왘 Shared Properties: Der Shared Property Manager ermöglicht gemeinsame Datenbereiche für alle Instanzen (auch verschiedener Klassen) innerhalb eines Package. 왘 Just-in-Time-Activation: Der MTS 2.0 kennt einen Object Caching-Mechanismus (Just-in-Time-Activation) – Komponenten verbleiben auch nach Deaktivierung der letzten Objektinstanz noch für eine bestimmte, definierbare Zeit im Speicher, um bei einer erneuten Anfrage schneller neue Instanzen bilden zu können. Dieser Mechanismus ist auch der Grund dafür, dass Entwickler oft vergeblich versuchen, COM-DLLs zu ersetzen. Solange die pro Package einstellbare Caching-Zeit seit der letzten Verwendung nicht verstrichen ist, muss das Package im MTS Explorer manuell – mit Hilfe des Kontextmenüeintrags Herunterfahren – entladen werden. Object Caching ist kein Object Pooling, bei dem die einzelnen Instanzen erhalten bleiben. Dies ist erst in COM+ implementiert. Just-in-Time-Activation kann seine Wirkung erst in Zusammenhang mit zustandslosen Komponenten voll entfalten.
7.24.3
Packages
Der MTS unterscheidet zwischen nichtkonfigurierten und konfigurierten Klassen. Erstere MTSsind Klassen, die lediglich installiert, also in der Registrierungsdatenbank als COM-Klasse Packages registriert sind. Sie sind jedoch nicht Teil eines MTS-Packages. Konfigurierte Klassen sind in einem so genannten MTS-Package enthalten. Ein Package ist die zentrale Organisationseinheit des MTS. Es besteht aus einer oder mehreren COM-Klassen. Unterstützt werden nur Klassen aus COM-In-process-Komponenten (d.h. COM-DLLs). Jede Klasse gehört zu höchstens einem Package. Nur Klassen, die in einem Package eingetragen sind, können die MTS-Zusatzdienste nutzen.
135
7 Das Component Object Model (COM)
Es gibt zwei Arten von Packages: Library Packages
왘 Bei Library Packages laufen die Klassen im Prozess des Aufrufers, was voraussetzt, dass
Server Packages
왘 Der Normalfall sind jedoch die Server Packages, die in einem eigenen Prozess laufen.
sich der aufrufende Prozess auf dem gleichen Computer befindet. Nur dieser Typ unterstützt alle Funktionen. Der gesamte Datenspeicher des MTS trägt den Namen MTS-Katalog.
7.24.4 GetObjectContext()
Programmierung
Die Instanzen einer Klasse, die im MTS bzw. als COM+-Anwendung laufen, können Zugriff auf die Interception-Umgebung erhalten: Nach Einbindung der Microsoft Transaction Server Type Library (mtxas.dll) steht die globale Funktion GetObjectContext() zur Verfügung, die einen Zeiger auf ein ObjectContext-Objekt mit einer IObjectContext-Schnittstelle liefert. Die Schnittstelle bietet hauptsächlich Funktionen zur Transaktionssteuerung (SetComplete, SetAbort, EnableCommit, EnableAbort, IsInTransaction) an. Während SetComplete und SetAbort das endgültige Ende einer Transaktion festlegen, kann mit EnableCommit und EnableAbort ein Zwischenstatus gesetzt werden. Zusätzlich kann der Komponentenprogrammierer Sicherheitsinformationen auslesen. Die zuvor beschriebene Form der Sicherheitseinstellung wird in COM auch als deklarative Sicherheit bezeichnet, bei der programmatischen Sicherheit wird dagegen innerhalb der COM-Objekte auf Sicherheitsfunktionen zugegriffen. MTS stellt das Rollenkonzept auch für die programmatische Sicherheit bereit. Innerhalb einer Klasse kann der Komponentenprogrammierer über die IObjectContext-Schnittstelle auf die Sicherheitsinformationen zugreifen. IObjectContext bietet die Methoden IsSecurityEnabled() und IsCaller InRole() sowie das Unterobjekt Security vom Typ Security Property.
7.25 COM+ COM+ ab Windows 2000 Bild 7.29: Verhältnis von COM, MTS und COM+
COM+ ist die Weiterentwicklung von COM, die mit Windows 2000 eingeführt wurde. COM+ umfasst COM und den Microsoft Transaction Server sowie weitere Dienste. Weitere Informationen zu COM+ finden Sie in [SCH00a] und [PLA99].
COM+ MTS COM
136
COM+
7.25.1
Änderungen gegenüber dem MTS
Die Funktionen des MTS 2.0 wurden aber nicht eins zu eins in COM+ übernommen. Fol- MTS versus COM+ gende Dinge sind anders: 왘 Das, was im MTS Package genannt wurde, heißt nun COM+ Application Der Name
Application
„Application“ ist natürlich sehr ungünstig gewählt, da es dafür in der COM-Welt mindestens schon zwei Bedeutungen gibt. 왘 In COM+ unterliegt jede Klasse automatisch dem Interception-Modell. COM+ benötigt
Interception
daher keine zwischengeschaltete mtx.exe mehr. Die Interception findet hier bereits vor dem Client-Proxy und vor dem Server-Stub statt. Die Erhebung einer DLL in einen eigenen Prozess leistet das bereits seit NT 4.0 Service Pack 2 ausgelieferte Standard-Surrogat dllhost.exe. Für Anwendungen, die 3 Gbyte Speicher unterstützen, wird dllhst3g.exe verwendet. Für den Komponentenprogrammierer vereinfachen sich durch die automatische Interception einige Funktionen. 왘 Der COM+ Catalog (der zentrale Datenspeicher von COM+, der dem MTS Catalog ent-
Daten-
왘 Die Administration erfolgt über ein geändertes Snap-In, das im Rahmen der MMC-
Administra-
왘 Bei der rollenbasierten Sicherheit unterstützt COM+ nun sogar die Zuordnung von
Rollen
spricht) wird nicht in der Registrierungsdatenbank, sondern in der so genannten COM+ speicher Registration Database (RegDB) gespeichert. Die RegDB befindet sich im Verzeichnis / WinNT/Registration.
Konfiguration Komponentendienste im Verwaltungsordner im Start-Menü zu finden ist. tion Rollen auf Methodenebene.
왘 Die Möglichkeiten des Zugriffs auf die Identität der Aufrufer in einer Kette von Objekt-
Aufrufketten
aufrufen wurde verbessert: Während bei MTS nur die Identität des direkten und die des ursprünglichen Aufrufers in einer Kette von Objektaufrufen ermittelbar ist, besteht unter COM+ Zugriff auf die komplette Liste der Benutzerkontexte, über die ein Aufruf gelaufen ist. COM+ bietet ein eigenes Objektmodell für den Zugriff auf die Sicherheitsinformationen. Den Einstieg bildet ein SecurityCallContext-Objekt, das wie das ObjectContext-Objekt über eine globale Methode (GetSecurityCallContext()) im Zugriff ist. 왘 COM+-Anwendungen können als ein Microsoft Windows Installer-Paket (.msi) expor-
MSI
tiert werden. 왘 Das Objektmodell für den Zugriff auf den Objektkontext hat sich geändert und heißt
Objekt-
jetzt COM+ Service Type Library (comsvcs.dll). Unter COM+ verfügt das Object modelle Context-Objekt über weitere Schnittstellen (IObjectContextInfo, IContextState und ISecurityCallContext), die den Zugriff auf Detailinformationen und ein Feintuning von Transaktionen ermöglichen. 왘 Ebenso hat sich das Objektmodell für die automatisierte Administration geändert. Es gibt nun eine Komponente mit Namen COM+ Administration Objects.
137
7 Das Component Object Model (COM)
7.25.2
Neue Dienste in COM+
COM+ unterstützt die folgenden neuen Dienste: Object Pooling
왘 Object Pooling: Das Object Pooling geisterte schon in Zusammenhang mit dem MTS
2.0 durch die Fachwelt, war jedoch nicht implementiert. Object Pooling ist die Möglichkeit, einen bestimmten Vorrat an Instanzen dieser Ressourcen im Speicher vorzuhalten, die dann bei Bedarf aktiviert werden. In COM+ gibt es für das Object Pooling nun ein Eigenschaftenfenster, in dem eine Unter- und eine Obermenge von Instanzen einer jeden Klasse definiert werden können, die im Speicher gehalten werden. Allerdings funktioniert Object Pooling nur mit Objekten im Multithreaded oder Neutral Apartment – also nicht mit Visual Basic 6.0-Klassen. Jede Instanz hat selbst die Möglichkeit, zu kontrollieren, ob sie in den Pool aufgenommen werden möchte. Dazu dient die Schnittstelle IObjectControl.
Object 왘 Object Construction String: Eine einfache Möglichkeit zur Übergabe von InformatioConstrucnen an Klassen besteht in COM+ mit dem so genannten Object Construction String. Im tion String
Komponentendienste-Snap-In kann zu jeder Klasse ein beliebige Zeichenkette eingegeben werden, der der Klasse bei der Aktivierung übergeben wird, sofern sie die Schnittstelle IObjectConstructionString implementiert.
Compensa- 왘 Compensating Resource Manager: Der Compensating Resource Manager ermöglicht ting Resource es, Ressourcen, für die kein eigener Resource Manager zur Verfügung steht, in TransakManager
tionen zu integrieren. So kann auch das Ergebnis eines Verarbeitungsprozesses, der gar nicht auf Datenbanken beruht, Teil einer Gesamttransaktion sein.
Queued Components
왘 COM+ Queued Components: Queued Components sind eine Integration des Micro-
Lose gekoppelte Ereignisse
왘 COM+ Events: In Abänderung zum klassischen COM ermöglicht ein spezieller Win-
soft Message Queue Servers (MSMQ) und ermöglichen den asynchronen Aufruf von Methoden. dows-Dienst, der COM+ Event Service, die Realisierung von lose gekoppelten Ereignissen. Dabei ist im Gegensatz zum Connection Point-Mechanismus (vgl. Kapitel 7.12) eine Filterung der Ereignisse möglich.
Laufzeit- Laufzeitumgebung Aus der ursprünglich in [KIR98] angekündigten einheitlichen umgebung Laufzeitumgebung für Komponenten und aus dem Class Store (Speicherung der Kompo-
nenteninformationen im Active Directory) ist in den COM+ Versionen 1.0 (Windows 2000) und 1.5 (ab Windows XP) nichts geworden. COM+ und .NET
Der Nachfolger von COM+ sollte ursprünglich COM+ Version 2.0 oder 3.0 heißen. Daraus wurde das .NET Framework. Die Dienste von COM+ leben aber auch im .NET Framework unter dem Namen .NET Enterprise Services weiter.
7.25.3
COM+-Administration
Zusammen- Die Konfiguration von COM+-Anwendungen erfolgt über das Komponentendienste-Snapsetzung einer In in der Management Console. Über das Snap-In kann auf entfernte COM+-Kataloge COM+-Anwendung zugegriffen werden. Das Snap-In wird im Kapitel 18 „Werkzeuge“ beschrieben.
138
Objektmodelle in COM-Komponenten
7.26 Objektmodelle in COM-Komponenten Unter den Entwicklern von COM-Komponenten ist die Verwendung von Objektmodellen COM-Objektsehr verbreitet. Die folgenden Ausführungen sind eine wichtige Grundlage für das Ver- modelle ständnis der in diesem Buch beschriebenen Objektmodelle administrativer Komponenten. Bitte beachten Sie auch die grafische Notation, die in Anhang B erläutert wird.
7.26.1
Objektorientierte Konzepte in COM
Hier soll kurz dargestellt werden, wie Polymorphismus, Mehrfachschnittstellen und Vererbung durch COM realisiert werden. Polymorphismus in COM COM unterstützt Polymorphismus in drei Formen: 왘 Zwei Schnittstellen, die von der gleichen Schnittstelle abgeleitet sind, verhalten sich
Polymorphismus
polymorph zueinander. So ist es möglich, dass ein Aufruf von QueryInterface() auf jeder von IUnknown abgeleiteten Klasse funktioniert. 왘 Zwei Klassen (und damit deren Instanzen) sind hinsichtlich jener Schnittstellen polymorph (siehe Anhang A), die beide Klassen implementieren. So kann auch ein früh bindender COM-Client Instanzen unterschiedlicher Klassen verwenden. 왘 Schließlich sind zwei Klassen auch dann polymorph, wenn sie über IDispatch-Schnittstellen verfügen, die jeweils eine Methode mit dem gleichen Namen und der exakt gleichen Signatur bereitstellen. So kann ein COM-Client via Automation eine Methode TueEtwas(was,wann) auch dann erfolgreich in zwei Instanzen unterschiedlicher Klassen ausführen, wenn die Methode TueEtwas() in beiden Klassen zu verschiedenen benutzerdefinierten Interfaces gehört. Voraussetzung ist lediglich, dass beide Methoden über die Parameter was und wann verfügen und die Datentypen gleich oder zumindest implizit konvertierbar sind. Letzteres kann einen vTable-fähigen Client dazu veranlassen, freiwillig auf die langsamere COM-Automation zurückzugreifen. Mehrfachschnittstellen und Versionierung Die Mehrfachschnittstellen in COM sind Grundlage der Versionierung (Versionierung Mehrfachbedeutet die parallele Bereitstellung verschiedener Versionen). Bei einer Änderung der schnittstellen Schnittstelle kann ein COM-Server neben der neuen auch die alte Schnittstelle unterstützen. Dadurch kann ein alter Client die Komponente weiterhin nutzen. Neuere Versionen einer Schnittstelle werden in COM oft durch Versionsnummern (z.B. IMachWas2) oder den Zusatz Ex für Extended (z.B. IMachWasEx) bezeichnet. Es ist dabei natürlich möglich, dass für Methoden, deren Implementierung unverändert geblieben ist, sowohl die Methode IAltes Interface::MethodeX als auch die Methode INeuesInterface::MethodeX auf die gleiche Implementierung verweist. Dieses Verfahren wird üblicherweise bei der Standardmethode IUnknown::QueryInter face() angewendet, die von jeder Schnittstelle implementiert werden und per definitionem die gleiche Aufgabe erfüllen muss. Es ist auch möglich, IUnknown::QueryInterface() so zu
139
7 Das Component Object Model (COM)
implementieren, dass die Anfrage nach einer veralteten Schnittstelle automatisch einen Zeiger auf die vTable einer neueren Schnittstelle liefert. Vererbung Vererbung
COM unterstützt keine Implementierungsvererbung, sondern nur die Schnittstellenvererbung. Die Wiederverwendung von Komponenten ist dennoch durch Aggregation und Delegation möglich. Da dies jedoch sehr weit in den Bereich des Komponentenentwurfs hineingeht, soll es an dieser Stelle bei dieser Erwähnung belassen werden. Mit der Vererbung in Visual Basic .NET (7.0) wird auch das Erben von COM-Klassen möglich. Diese Funktion wird allerdings nicht durch COM selbst, sondern durch den Visual Basic-Compiler bzw. die Visual Basic-Laufzeitumgebung bereitgestellt.
7.26.2
Bausteine von COM-Objektmodellen
Eine COM-Komponente kann beliebig viele Objektmodelle enthalten. Viele Komponenten bestehen jedoch aus nur einem einzigen großen Objektmodell. In COM bestehen Klassendefinitionen aus Attributen, Methoden und Ereignissen. Objektmodelle entstehen, indem Attribute auf andere Objekte verweisen oder Methoden Zeiger auf andere Objekte zurückliefern. Klassentypen In COM-Objektmodellen gibt es üblicherweise vier Typen von Klassen, die auf Grund von
zwei Kriterien gebildet werden: 왘 Einerseits unterscheidet man Klassen, die einen Behälter für eine Menge von Objekten
darstellen (so genannte Objektmengen), und Klassen, die Einzelobjekte repräsentieren. 왘 Andererseits unterscheidet man, ob eine Klasse von außen durch den Komponenten-
benutzer instanziierbar ist oder nur intern von Instanzen anderer Klassen instanziiert werden kann. Collections
Objektmengenklassen versus Einzelklassen In COM wird die in Anhang A diskutierte Unterscheidung zwischen Set, Bag und Collection nicht vorgenommen. In der COMWelt werden Objektmengen unabhängig davon, ob die enthaltenen Instanzen homogen oder heterogen sind, Objektmengen genannt. Man sagt auch, eine Objekthierarchie bestehe aus Objekten und Objektmengen (obwohl letztere natürlich auch Objekte sind). In der Regel ist die Anzahl der Unterobjekte einer Objektmenge variabel. Häufig gibt es in COMKomponenten auch Objektmengen, die die Aufnahme von Unterobjekten auf Instanzen einer bestimmten Klasse beschränken (was in der Theorie ein Set genannt wird).
Collec- Objektmengen in COM besitzen in der Regel eine Verwaltungsklasse. Diese Verwaltungsklastionklassen sen werden in Abgrenzung zu Einzelklassen Objektmengenklassen (engl. Collection) genannt. versus Einzelklassen Einzelklassen sind nicht in der Lage, eine Menge von Objekten zu verwalten. Der Begriff Col-
lection wird insofern doppeldeutig verwendet, als damit einerseits nur die Verwalterklasse bezeichnet wird, andererseits auch alle in der Objektmenge enthaltenen Objekte. Zirkuläre Referenzen
140
In COM kommen n-zu-m-Beziehungen eher selten vor, da dies zirkuläre Referenzen bedingt. Zirkuläre Referenzen bringen Probleme bei der Freigabe von Speicherplatz mit sich.
Objektmodelle in COM-Komponenten
1-zu-1-Beziehung Klasse A
1-zu-n-Beziehung
Klasse A
Klasse A Klasse B
Bild 7.30: Modellierung der Nutzungsbeziehungen mit verschiedenen Kardinalitäten in COM
n-zu-m-Beziehung
Collection C
Collection C Klasse B
Klasse B Collection D
Es ist möglich, dass ein Objektmodell sich über Klassen aus mehreren Komponenten erstreckt. Dies kommt jedoch selten vor. Die Microsoft Shell Objects sind ein Beispiel dafür (siehe Kapitel 13.1 zu den Shell Objects). Instanziierbare versus nichtinstanziierbare Klassen COM-Komponenten verfü- Instanziiergen in der Regel nur über wenige instanziierbare Klassen. In einigen Fällen ist nur das barkeit Stammobjekt selbst instanziierbar. Eine Komponente mit einer einzigen Stammklasse schließt die eigenständige Instanziierbarkeit von untergeordneten Klassen nicht aus. In diesem Fall wird in dem Objektbaum nicht an der Wurzel begonnen, sondern an einem Ast, Zweig oder Blatt. Dann sollte jedoch eine Navigationsmöglichkeit zurück zu den in dem Objektmodell übergeordneten Objekten angeboten werden.
7.26.3
Empfehlungen für Objektmodelle
Microsoft hat mit den COM-Objektmodellen aus Objektmengen und Objekten ein Rah- Gutes Objektmenwerk geschaffen, das eine große Bandbreite möglicher Realweltsituationen abbilden modelldesign kann. Es gibt einige Empfehlungen (Best Practices), wie diese Objektmodelle verwendet werden sollten: 왘 Ein Objektmodell sollte genau eine Stammklasse besitzen, über deren Instanz der Zugriff
Stammklasse
auf die Instanzen der anderen Klassen möglich ist. Sofern es sich bei der COM-Komponente um eine eigenständige Anwendung handelt, sollte die Stammklasse Application heißen (vgl. [MIC98], S. 718). 왘 Der Weg von einem Objekt zu einem untergeordneten Objekt oder einer Objektmenge
Attribut-
sollte über ein Attribut erfolgen, das den gleichen Namen trägt wie der Klassenname des namen Objekts bzw. der Objektmenge. 왘 Als Weg zurück von einem untergeordneten Objekt zu Objekten, die in der Objekthierarchie darüber liegen, werden folgende Möglichkeiten verwendet: 왘 Über ein Attribut hält jede Klasse einen Verweis auf das Stammobjekt bereit. Dieses
Attribut hat den Namen der Stammklasse (also meistens Application). Der Anwender kann dann vom Stamm aus zu allen Objekten navigieren. 왘 Über ein Attribut Parent hält jede Klasse einen Verweis auf das im Baum nächst-
höhere Objekt bereit. Dadurch ist eine schrittweise Navigation von den Blättern des Baums bis zurück zum Stamm möglich.
141
7 Das Component Object Model (COM)
Benennung von Objektmengen
왘 Eine homogene Objektmenge sollte den gleichen Namen haben wie die Klasse der
Objektmengenmethoden
왘 Eine Objektmenge sollte die Methoden Add(), Insert() und Remove() sowie das Attri-
Attribut oder Methode?
Objekte, die sie enthält, jedoch im Plural. (Beispiel: Eine Objektmenge von File-Objekten heißt Files.) Nur wenn Singular und Plural des Begriffs gleich sind (z.B. Fenster), sollte die Objektmenge durch ein Suffix (z.B. FensterListe) kenntlich gemacht werden (vgl. [MIC98], S. 706f.). but Item() anbieten. Außerdem sollte sie die zur Unterstützung von For...Each benötigte Methode _NewEnum besitzen. _NewEnum soll eine versteckte Methode sein ([MIC98], S. 716ff.). 왘 In einer Objektmenge sollte eine Methode, die ein extern erstelltes Objekt in eine Objektmenge aufnimmt, Insert() heißen. Die Methode Add() sollte selbst eine Instanz der gewünschten Klasse erzeugen und zurückgeben. 왘 Item() sollte den Zugriff sowohl über einen fortlaufenden numerischen Index als auch über einen alphanumerischen Schlüssel unterstützen. Da Item() immer einen Parameter erwartet, müsste es sich eigentlich um eine Methode und nicht um ein Attribut handeln. Item()-Attribut oder Item()-Methode? Die Frage, ob Item() ein Attribut oder eine Methode ist, ist nicht trivial. Die Tatsache, dass Item() einen Parameter hat, spricht für eine Methode. Die Tatsache, dass in vielen Komponenten Zuweisungen an Item() erfolgen können (z.B. objDic.Item(key) = Wert in der Klasse Scripting.Dictionary), spricht dagegen für ein Attribut. Microsoft selbst ist nicht ganz eindeutig: Einerseits spricht man von Item() als Methode (z.B. [MIC98, S. 717], [MSD01i], [MSD01k]), andererseits von einem Attribut (z.B. [MSD01h], [MSD01g]). Dass Microsoft sich nicht einig ist, wird ganz deutlich in [MSD01j]: Das Dokument heißt vbmthItemMethodActiveXControls.asp, die Überschrift lautet aber Item Property. Der Microsoft-Objektkatalog zeigt, dass in einigen Objektmengenklassen Item() als Attribut definiert ist (z.B. Scripting.Drives, ADODB.Parameters oder MAPI.Folders), während in anderen Objektmengenklassen Item() eine Methode ist (z.B. SQLDMO.Jobs, WbemScripting.SWbemObjectSet oder SHDocVw.ShellWindows). Für COM selbst ist der Unterschied egal, da es in COM auf der Binärebene nur Methoden gibt.
7.26.4
Metaobjektmodelle
Probleme Die Definition eines Objektmodells kann durch zwei Umstände erschwert werden: mit Objektmodellen 왘 Komplexität: Oft ist der durch Objektmodelle abgebildete Realweltausschnitt sehr kom-
plex. Wenn es sehr viele Elementtypen in der Realwelt gibt, dann sind in der Regel auch viele Klassen nötig, um diese Welt zu modellieren. 왘 Erweiterbarkeit: Wenn es in der Realität vorkommt, dass Elementtypen sich in einem Zeitablauf in ihrem Aufbau ändern oder neue Elementtypen hinzukommen können, dann muss das Schema der Komponente (insbesondere das Objektmodell) angepasst werden. COM ist jedoch nicht darauf ausgelegt, dass sich das Schema einer Komponente zur Laufzeit ändert. Jede Änderung bedeutet also eine Neukompilierung der Komponente. Metaobjektmodelle
142
Diesen Anforderungen wird inzwischen in einigen Fällen durch ein Konzept begegnet, das hier Metaobjektmodell genannt werden soll. Ein Metaoobjektmodell ist eine Abstraktion
Objektmodelle in COM-Komponenten
von einem konkreten Objektmodell. Ein solches Metaoobjektmodell definiert einen allgemeinen Satz von (Universal-)Klassen (auch: Metaklassen), mit denen ein Zugriff auf ein anderes Objektmodell möglich ist. Dabei findet eine Abbildung statt: Eine Klasse des Metaobjektmodells wird auf n Klassen des Basisobjektmodells abgebildet. Diese Metaklasse bietet Funktionen, um auf die Schnittstellen der Basis-Klasse zuzugreifen. Eine Sonderform bilden Metaoobjektmodelle, die eine 1-zu-n-Abbildung nur auf Ebene von Attributen und Methoden realisieren. Es gibt in diesen Objektmodellen zu jeder BasisKlasse auch genau eine Klasse im Metaoobjektmodell. Allerdings kann es in der BasisKlasse mehr Mitglieder geben als in der Metaklasse. Für die zusätzlichen Mitglieder bietet die Metaklasse ein Konstrukt an. Wie auch schon bei dem Begriff Objektmodell ist an dieser Stelle der Hinweis notwendig, dass der Begriff Metaobjektmodell auf Modellierungsebene anders verwendet wird. Dort ist ein Metaobjektmodell eine weitere Abstraktionsebene über einer Beschreibung der Elemente einer objektorientierten Modellierung.
Andere Definition
Auch ein Metaobjektmodell wird in einer COM-Komponente implementiert. Dabei unterscheidet sich eine solche Metakomponente aus der Sicht von COM in keinster Weise von einer anderen Komponente. Der Unterschied liegt in der Semantik des implementierten Objektmodells. Ein Basisobjektmodell kann auch wieder in Form einer COM-Komponente implementiert sein, muss es aber nicht. In der Praxis sind die Basisobjektmodelle meist in anderer Form realisierte Objektmodelle. Bindung in Metaobjektmodellen In der Regel ist vorgesehen, dass der Client nur Bindung mit dem Metaobjektmodell, nicht auch mit dem konkreten Objektmodell arbeitet. Er instanziiert eine Klasse aus dem Metaobjektmodell und bindet diese Instanz dann an ein Objekt aus dem Basisobjektmodell, wobei die Bindung in der Regel an konkrete Instanzen dieses Modells erfolgt. Danach ermöglicht das Metaobjekt den Zugriff auf die Attribute und Methoden des konkreten Objekts. Meta-Objektmodell
Bild 7.31: Eine Metaklasse in einem Metaobjektmodell bildet eine Vielzahl von Klassen und Instanzen in einem konkreten Objektmodell ab.
Klasse Meta Klasse
Collection Klasse
Klasse B 0,1
Objekt B1 Klasse E
1
Objekt A1
* 1
Collection D1
Klasse D (Collection)
Klasse C
Schema
0,1
Klasse A
Objekt C1 Objekt C2
Klasse A
Instanzen
Objekt A2
Basis-Objektmodell
143
7 Das Component Object Model (COM)
Sofern das Basisobjektmodell jedoch über ein transparentes Schema verfügt, ist es üblich, dass das Metaobjektmodell nicht nur eine Abbildung der Instanzen des Basisobjektmodells, sondern auch eine Abbildung der Schema-Informationen zulässt. Beide Möglichkeiten zeigt Bild 7.27. In einem Metaobjektmodell-Konzept ist eine Klasse des Metaobjektmodells auch dafür zuständig, Instanzen im Basisobjektmodell zu erzeugen bzw. zu vernichten. Verfügbare Metaobjektmodelle
Metaobjektmodelle in COM Es gibt inzwischen im Bereich der COM-Komponenten für Windows einige Metaobjektmodelle, z.B. das Active Directory Service Interface (ADSI) und das Windows Management Instrumentarium Scripting API. Die ActiveX Data Objects (ADO) sind ein Metaobjektmodell auf Attributebene.
Unzureichende Dokumentation
Komponenten für Architekturen, die ein Provider-Konzept besitzen (z.B. ADSI, WMI, ADO, CDO/MAPI), sind geeignete Kandidaten für Metaobjektmodelle, da die Programmierschnittstelle mit unterschiedlichen Providern zusammenarbeiten kann. Allerdings zeigen die Dokumentationen dieser Komponenten, dass deren Autoren sich über die Unterschiede zwischen den Metaobjektmodellen und den Basisobjektmodellen wenig Gedanken gemacht haben; in der Regel wird dieser Unterschied stillschweigend übergangen. Dabei ist eine saubere Trennung der beiden Konzepte für das Verständnis einer COM-Komponente sehr wichtig. Hinsichtlich der Frage, wie die Abbildung eines konkreten Basisobjekts auf Metaobjekte erfolgt, kann man verschiedene Typen unterscheiden:
Typ 1
왘 Typ 1: Attribute und Methoden werden selbst wieder durch Metaobjekte repräsentiert.
Für die Attribute gibt es eine Objektmenge von Attribut-Metaobjekten, für die Methoden eine Objektmenge von Methoden-Metaobjekten. Die Attribut-Metaklasse stellt Methoden wie Get() und Set() bereit, um die Eigenschaften des konkreten Objekts zu modifizieren. Die Methoden-Metaklasse stellt eine Methode wie Execute() bereit, um eine Methode auf dem konkreten Objekt aufzurufen. Diese Vorgehensweise führt zu einer sehr aufwändigen und widersinnig wirkenden Codierung. Der Vorteil besteht darin, dass die Attribut- und Methoden-Metaobjekte gleichzeitig Schemainformationen bereitstellen können. Ein Client kann so zur Laufzeit erforschen, welche Attribute und Methoden das konkrete Objekt besitzt. Typ 2
왘 Typ 2: Eine Modifikation vom Typ 1 besteht darin, Attribute und Klassen nicht durch
eine eigene Metaklasse abzubilden, sondern die oben genannten Zugriffsmethoden direkt in der Metaklasse abzubilden, die das konkrete Objekt als Ganzes repräsentiert. Typ 3
왘 Typ 3 (Direct Access): Die dritte Möglichkeit ist, dass sich das Metaobjekt in Abhängig-
keit von der aktuellen Bindung verwandelt, so dass der Nutzer keinen Unterschied zwischen dem Metaobjekt und dem konkreten Objekt bemerkt. Das bedeutet, dass eine Metaklasse wie CIMObject nach der Bindung an ein Grundobjekt die Mitglieder des Grundobjekts so in seine IDispatch-Schnittstelle einbindet, dass Attribute und Methoden doch wieder über die übliche Mitglieder-Zugriffsnotation (z.B. obj.Methode) aufgerufen werden können. Eine solche Metaklasse ist also in der Lage, zur Laufzeit ihre IDispatch-Schnittstelle zu erweitern und die Grundklasse zu emulieren. Der Programmierer sieht keinen Unterschied mehr zwischen Meta- und Basisobjekt und kann auf natürliche Weise programmieren. Dieses Verfahren hat im Gegensatz zu den anderen Typen einen Namen: Direct Access.
144
Objektmodelle in COM-Komponenten
Der Nachteil des Direct Access ist, dass der Nutzer nicht mehr unterscheiden kann, welche Mitglieder der Metaklasse und welche der konkreten (emulierten) Klasse angehören. Kritisch könnte es bei Namensüberschneidungen werden. Es empfiehlt sich daher, per Namenskonvention eine Überschneidung zu verhindern. 왘 Typ 4: Während alle oben beschriebenen Typen in der COM-Welt bereits vorkommen, ist
Typ 4
dem Autor kein Metaobjektmodell bekannt, das eine Emulation über eine Mehrfachschnittstelle realisiert. Ein Metaobjekt würde neben der eigenen Standardschnittstelle, die unverändert bleibt, eine weitere Schnittstelle mit den Mitgliedern der Klasse des Basisobjektmodells anbieten. Damit COM-Automation-Clients davon Gebrauch machen können, müsste die Standardschnittstelle ein Attribut anbieten, um zu der zweiten Schnittstelle zu navigieren. Wenn das konkrete Objekt selbst Mehrfachschnittstellen besitzt, könnte das Metaobjekt auch diese abbilden: Für ein konkretes Objekt mit n Schnittstellen würde das Metaobjekt dann n+1 Schnittstellen anbieten. Das Metaobjekt ändert auch dabei seine Standardschnittstelle nicht, sondern fügt die Schnittstellen des konkreten Objekts hinzu. Damit COM-Automation-Clients davon Gebrauch machen können, müsste die Standardschnittstelle eine Methode GetInterface() anbieten, die die Navigation zu n Schnittstellen ermöglicht. Probleme bei den Eingabehilfen Metaobjektmodelle haben hinsichtlich der Unterstützung bei der Programmcodeeingabe den Nachteil, dass das Konzept der Typbibliotheken nur für die direkt angesprochene Komponente, also das Metaobjektmodell, nicht aber für das Basisobjektmodell funktioniert. Metaobjektmodelle sind eine Form des späten Bindens; der bisherige Mechanismus zur Typermittlung auf Basis der Typdeklaration kann also nicht wirken, da die Typdeklaration stets für die Metaklasse erfolgt. Eine Unterstützung für die Funktionen der Grundklassen wäre zwar denkbar (z.B. durch den Zugriff auf das Schema des Basisobjektmodells), ist aber heute noch an keiner Stelle implementiert. Beispiele für Metaobjektmodelle Im Folgenden sollen drei Beispiele für die Realisierung von Metaobjektmodellen vorgestellt werden. Die Realisierung ist dabei jeweils sehr unterschiedlich. 왘 Beispiel 1: WMI
Die Windows Management Instrumentation (WMI) abstrahiert am weitesten von den WMI eigentlichen Klassen. Die WMI-COM-Komponente definiert nur Metaklassen wie SWbemObject, SWbemMethod und SWbemProperty, deren Instanzen an Basisobjekte gebunden werden können. Attributzugriffe und Methodenaufrufe sehen in WMI dann folgendermaßen aus: wert = Obj.Properties_("Attributname") und Obj.Properties_("Attributname") = wert. Set method = process.Methods_("Create") Set inParam = method.inParameters.SpawnInstance_() inParam.CommandLine = "calc.exe" Set outParam = process.ExecMethod_("Create", inParam)
145
7 Das Component Object Model (COM)
Unterscheidung per Unterstrich
Da aber zusätzlich auch der direkte Zugriff angeboten wird, ist WMI ein Metaobjektmodell sowohl vom Typ 1 als auch vom Typ 3. WMI verwendet zur Trennung der Mitglieder der Metaklasse von den emulierten Mitgliedern einen Unterstrich nach den Namen der Metaklassen-Mitglieder. 왘 Beispiel 2: ADSI
ADSI
Das Active Directory Service Interface (ADSI) definiert einen Satz von Standardschnittstellen. ADSI-Provider können Klassen aus diesen Standardschnittstellen zusammensetzen, aber auch neue Schnittstellen implementieren. Jede Klasse muss jedoch über eine bestimmte Standardschnittstelle verfügen, die Methoden zur Erweiterbarkeit bereitstellt. Im Fall von ADSI sind dies u.a. die Methoden Put() und Get(). obj.Put("Attributname") = Wert Wert = obj.Get("Attributname")
ADSI ist also ein Metaobjektmodell vom Typ 2. Ein dynamischer Methodenaufruf ist nicht vorgesehen. 왘 Beispiel 3: DMO und ADO
DMO und ADO
Die Distributed Management Objects (DMO) und die ActiveX Data Objects (ADO) bieten direkten Zugriff auf die Grundobjekte und zusätzlich eine Erweiterbarkeit hinsichtlich der Attribute. Jede Klasse verfügt über eine Properties-Objektmenge mit Property-Objekten, die jeweils ein Attribut repräsentieren. Ein Property-Objekt liefert Informationen über Name, Typ, Wert sowie Eigenschaften des Attributs und kann auch zur Veränderung des Werts verwendet werden. Somit lassen sich dynamische Attribute realisieren. Die Art des Zugriffs entspricht Typ 1. Leider gibt es auch bei diesem Typ von dynamischen Objektmodellen keinen Standard. So verfügt ein Property-Objekt in ADO über die Attribute Name, Type, Value und Attributes. DMO verwendet dagegen Name, Type, Value, Get und Set.
7.27 Bewertung von COM COM-Kritik
146
Die COM-Welt könnte so schön sein, gäbe es da nicht einige Unzulänglichkeiten. Zunächst werden in diesem Unterkapitel Unzulänglichkeiten der COM-Spezifikation bzw. der COMImplementierung angesprochen. Anhand einiger real existierender Objektmodelle sollen dann Beispiele für schlechte Objektmodelle und Typbibliotheken aufgezeigt werden. Dies ist jedoch nur eine beispielhafte Auflistung, um Sie grundsätzlich für Problembereiche zu sensibilisieren. Weitere Informationen erhalten Sie im Rahmen der detaillierten Beschreibung der Komponenten in den folgenden Kapiteln.
Bewertung von COM
7.27.1
Vorteile von COM
Zunächst zu den unbestreitbaren Vorteilen von COM: 왘 COM ist ein Binärstandard für Komponenten und weitestgehend sprachunabhängig. 왘 COM ist in der Windows-Welt sehr weit verbreitet. 왘 COM unterstützt Mehrfachschnittstellen und bietet damit ein Instrument zur Versio-
nierung (Versionierung bedeutet die parallele Bereitstellung verschiedener Versionen) von Komponenten. 왘 COM ist integriert in die Windows-Sicherheit. 왘 COM bietet mit dem Dienst Distributed COM (DCOM) eine transportprotokollneutrale Middleware zur entfernten Nutzung von Komponenten. 왘 COM ist ein objektorientierter Ansatz, der verschiedene Konzepte der Objektorientierung unterstützt.
7.27.2
COM auf anderen Plattformen
Auf anderen Plattformen hat COM bislang kaum Bedeutung. Neben COMSource, der COMSource COM-Referenzportierung der Open Group für Solaris und True64UNIX [COS00], gibt es jedoch inzwischen auch Ansätze von Softwareherstellern, COM auf anderen Plattformen verfügbar zu machen (z.B. EntireX von der Software AG). Die COM-Spezifikation hat Microsoft im Jahre 1996 offiziell in die Verantwortung der Active Group Active Group, einem Zusammenschluss im Rahmen der Open Group, übergeben. Allerdings wird die Active Group ihrem Namen nicht gerecht und ist äußerst passiv – wie ein Blick auf die seit Jahren nicht mehr gewartete Homepage schnell enthüllt [AGR00]. COM ist faktisch weiterhin eine proprietäre Architektur, deren Weiterentwicklung allein Microsoft bestimmt. Diese Bewertung wird von Gruhn/Thiel [GRU00, Seite 260] und Chappell [CHA97, Seite 56] unterstützt. Immerhin gibt es auf den Webseiten der Open Group inzwischen eine COM-Referenz unter dem Namen „ActiveX Core Technology Reference“ [ATX00]. Auch hier wird also ActiveX nicht klar von COM abgegrenzt.
7.27.3
Unzulänglichkeiten von COM
Dieses Unterkapitel listet zunächst einige grundsätzliche Unzulänglichkeiten von COM auf. Danach folgt eine genauere Kritik an den Objektmodellen und Typbibliotheken vieler Komponenten. Die allgemeinen Unzulänglichkeiten von COM sind: 왘 Nicht alle COM-Sprachen können alle COM-Komponenten nutzen, da es zwei unter-
IDispatch
schiedliche Mechanismen zum Methodenaufruf (IUnknown und IDispatch) gibt. Leider unterstützen nicht alle COM-Komponenten beide Verfahren. 왘 Nicht alle Klassen verfügen über eine ProgID oder einen Friendly Class Name, die dem
Namen
Komponentennutzer die Bedeutung der Klasse offen legen.
147
7 Das Component Object Model (COM)
DLL-Hölle
왘 COM ermöglicht die Versionierung innerhalb einer Komponente durch Mehrfach-
schnittstellen. COM ermöglicht – zumindest vor Windows Whister – aber nicht die parallele Installation einer Komponente in verschiedenen (Unter-)Versionen und die eindeutige Zuordnung dieser Komponenten zu COM-Clients. So kommt es zur so genannten „DLL-Hölle“ (engl.: DLL Hell), wenn verschiedene COM-Clients jeweils eine andere Version einer Komponente für den korrekten Betrieb benötigen. Dieses Problem ist aber ab Windows XP durch die so genannten Side by Side Assemblies gelöst. Registrierungsdatenbank
왘 Die Einstellungsmöglichkeiten in der Registrierungsdatenbank sind zu unstrukturiert
Komponenten-Repository
왘 COM fehlt es an einem Komponenten-Repository, das Metainformationen über Kom-
Object Trader
왘 Es fehlt ein Object Trader, der auf Anfrage nach bestimmten Fähigkeiten eine entspre-
bzw. zu flexibel. Beispielsweise kann ein Entwickler gegen die Konventionen zum Aufbau einer ProgID verstoßen und den Anwender durch Inkonsistenzen zwischen ProgID, Typbibliotheksname, Typbibliothek-Helpstring und Friendly Name einer Klasse vollkommen verwirren. ponenten in strukturierter Form speichert. Die COM-Informationen in der Registrierungsdatenbank werden den Anforderungen an Metainformationen über Komponenten nicht gerecht. chende Klasse ermittelt. Die Möglichkeit der Zuordnung zu Komponentenkategorien ist unzureichend.
Laufzeit- 왘 Eine einheitliche Laufzeitumgebung für COM-Komponenten ist bislang nicht vorhanumgebung den. Es ist definiert, wie Komponenten auf binärer Ebene genutzt werden sollen; aus der
Sicht des Programmierers ergeben sich jedoch je nach Sprache, in der der COM-Client implementiert werden soll, große Unterschiede in der Art des Umgangs mit den Komponenten. Vererbung
왘 COM bietet keine Mechanismen zur Implementationsvererbung. Diese kann bislang
allenfalls durch eine sprachspezifische Laufzeitumgebung (z.B. Visual Basic 7.0) geschaffen werden. Dokumentation
왘 Nicht alle COM-Komponenten sind dokumentiert. Ohne Dokumentation bleibt nur
die Selbsterforschung auf Basis von Typbibliotheken.
Typbibliothek 왘 Nicht alle COM-Komponenten verfügen über eine Typbibliothek. Ohne eine solche ist die
Erforschung einer (undokumentierten) Komponente allerdings nicht möglich. Ebenso stehen die Unterstützungsfunktionen zur Codeeingabe ohne Typbibliothek nicht zur Verfügung. Objektmodelle
왘 Die Objektmodelle in den COM-Komponenten sind oft so uneinheitlich, dass keine
intuitive Nutzung möglich ist. Schlechte Objektmodelle
Kritik an Der letzte der oben genannten Punkte wiegt besonders schwer aus der Sicht von Programbestehen- mierern und Administratoren, die sich ständig in neue Komponenten einarbeiten sollen. den Objektmodellen Außer den wenigen Empfehlungen von Microsoft gibt es keine Richtlinien für die Umset-
zung von Objektmodellen. Leider verstößt Microsoft selbst häufig gegen die eigenen Empfehlungen, wie folgende Beispiele für von Microsoft herausgegebene Komponenten zeigen:
148
Bewertung von COM
왘 Einige Objektmengen (z.B. in der WSH Runtime Library) enthalten keine Objekte, son-
dern eine Menge elementarer Datentypen. Die Effizienz mag höher sein, wenn sowieso nur ein Attribut pro Objekt zu verwalten ist. Die Konsistenz leidet allerdings darunter.
왘
왘
왘
왘
왘
왘 왘
왘
Im Fall der Klasse WSHNetwork gibt es zwei Objektmengen, bei denen jeweils ein Unterobjekt mit zwei Attributen notwendig gewesen wäre. Statt einer korrekten Implementierung mit Unterobjekten hat sich Microsoft jedoch unverständlicherweise für eine Liste von Zeichenketten entschieden, in der die beiden notwendigen Attribute abwechselnd enthalten sind. Nicht immer heißt ein Attribut, das auf ein Unterobjekt verweist, wie die Klasse des Unterobjekts. Einen identischen Namen zu wählen, ist zwar grundsätzlich nur dann möglich, wenn maximal ein Objekt dieser Klasse existiert; dennoch hält sich Microsoft auch dann nicht daran, wenn es möglich wäre. Bei ADSI spricht Microsoft nicht von Objektmengen, sondern verwendet die aus der Welt der Verzeichnisdienste stammende Bezeichnung Container. Die Methode zur Erzeugung neuer Instanzen in einem Container heißt Create() und nicht Add(). Das Löschen erfolgt über Delete() statt über Remove(). Die Klassen SecurityCallContext und SecurityIdentity in der COM+ Services Library wurden als Objektmengen implementiert, obwohl es nur eine feste Anzahl von Attributen bzw. Unterobjekten gibt. Dies führt dazu, dass Attribute nicht mehr über die übliche Punktnotation, sondern völlig untypisch über den Zugriff auf die Item()-Methode angesprochen werden können. In den COM+ Administration Objects sind alle Objektmengen beim ersten Zugriff zunächst einmal leer. Erst der Aufruf der Methode Populate() ermöglicht den Zugriff auf die enthaltenen Objekte. Und noch einmal die COM+ Administration Objects: Der Zugriff auf Objektmengen erfolgt nicht über Attribute des übergeordneten Objekts, sondern über die Methode GetCollection() auf der Ebene der Objektmenge, die über dem übergeordneten Objekt liegt. GetCollection() benötigt dazu einen eindeutigen Bezeichner für das übergeordnete Objekt und den Namen der diesem Objekt untergeordneten Objektmenge, auf die zugegriffen werden soll. Die unterschiedliche Art und Weise, Metaobjektmodelle zu implementieren, wurde schon im vorherigen Kapitel ausführlich besprochen. Leider kann man bei den Microsoft-Objektmodellen oft vom Namen eines Mitglieds nicht darauf schließen, ob es sich um ein Attribut oder eine Methode handelt: So ist GetFolder() in der Klasse Shell32.FolderItem ein Attribut; die Verweise auf untergeordnete Objektmengen sind dagegen in der gleichen Komponente als Attribute deklariert. Die vorhandenen Komponenten-Dokumentationen in der MSDN Library sind nicht einheitlich und oft zu wenig strukturiert. Die Art der Auflistung der Klassen, ihrer Schnittstellen, Methoden, Attribute und Ereignisse ist von Komponente zu Komponente grundverschieden. Zudem gibt es selten eine grafische Darstellung der Objektmodelle in der Dokumentation. Das erschwert die Einarbeitung in neue Komponenten und stellt den Microsoft-Kunden vor die Frage, wie es sein kann, dass ein solches Unternehmen keine Standards für die Dokumentation von Software hat.
149
7 Das Component Object Model (COM)
Zukunft
Zukunft Leider werden diese schlechten Objektmodelle die Windows-Programmierer auf sehr lange Zeit verfolgen: Aus Kompatibilitätsgründen erfolgt ein grundsätzlicher Umbau von Objektmodellen nur selten. Umso wichtiger wäre es, Objektmodelle von Beginn an nach den festgesetzten Prinzipien zu erstellen. Man merkt, dass Microsoft zwar das Prinzip der Arbeitsteilung bei der Entwicklung der Komponenten beherrscht, jedoch nicht in der Lage ist, zwischen den Entwicklungsteams eine gute Kommunikation herzustellen. Ein wichtiger Tipp: Halten Sie sich bei Ihren selbst erstellten Objektmodellen an die Modellierungsempfehlungen! Schlechte Typbibliotheken
Kritik an Kritikpunkte finden sich auch bei den COM-Typbibliotheken: bestehenden Typbiblio- 왘 Die Typbibliotheken geben manchmal nur einen Teil der vorhandenen Schnittstellen theken wieder. 왘 Anstatt Klassen und ihre Schnittstellen zu definieren, beschränken sich viele Typbiblio-
theken auf die Schnittstellen. Viele Typbibliotheken enthalten Klassenbeschreibungen nur für die instanziierbaren Klassen. Der Objektkatalog zeigt in diesem Fall die nichtzugeordneten Schnittstellen mit Namen der Form IName als Klassen an (z.B. msxml.dll, siehe [SCH01c]). 왘 Einige Klassennamen in den Typbibliotheken verhalten sich zu den Registrierungsdatenbankeinträgen inkonsistent (z.B. bei der WSH Runtime Library, MSHTML und der Zeitplandienst-Komponente). 왘 In einigen Typbibliotheken werden die Namenskonventionen verletzt. Zum Beispiel heißen Klassen in der WSH Runtime Library IWSHShell_Class und IWSHNetwork_Class. Ein anderes Beispiel sind die Schnittstellennamen in den Collaboration Data Objects (CDO), die nicht mit einem großen I beginnen. In der Zeitplandienst-Komponente heißen einige Schnittstellen Idisp[Name]. Das „disp“ soll dabei auf die Existenz einer IDispatchSchnittstelle verweisen. Das ist insofern zu kritisieren, als dies entweder durchgängig bei allen Komponenten erfolgen sollte oder gar nicht. Positivbeispiel
Um auch ein Beispiel zu nennen, in dem es richtig gemacht wurde: scrrun.dll (Scripting Runtime Library). Hier besitzt eine Klasse wie File eine Schnittstelle IFile.
7.28 .NET Framework („DOTNET“) Das Microsoft .NET Framework ist die Weiterentwicklung von COM und dennoch ein völlig neues Komponentenmodell. Das .NET Framework wird in Zusammenhang mit der PowerShell in Buchteil C besprochen.
150
8
Die Visual BasicSprachfamilie
Dieses Kapitel liefert Ihnen eine kompakte Einführung in die Programmiersprache Visual VBS, VBA, Basic, wobei der Schwerpunkt auf dem kleinsten Mitglied der Sprachfamilie, VBScript VB 6.0 (VBS), liegt. Aber auch die großen Brüder, die „Vollversion“ Visual Basic 6.0 (VB 6.0) und Visual Basic for Applications (VBA), finden Berücksichtigung. Soweit nicht anders erwähnt sind alle Beispiele in diesem Buch in VBScript geschrieben, aber auch in den anderen Dialekten lauffähig. Das neue Visual Basic .NET (VB.NET) ist in vielen Punkten anders als die anderen Mitglie- VB.NET der der VB-Sprachfamilie. Die Aussagen in diesem Kapitel lassen sich nicht komplett auf VB.NET übertragen. Auf die Darstellung anderer (Script-)Sprachen wird an dieser Stelle bewusst verzichtet, um die Komplexität der Komponentendokumentation und der Automatisierungslösungen nicht durch den Wechsel zwischen verschiedenen Sprachen zu erhöhen. VBScript ist die verbreitetste Scriptsprache im Windows-Bereich und bietet sich auf Grund der starken Synergieeffekte mit VB 6.0 und VBA als zentrale Sprache in diesem Buch an. Bewusst werden die Unterschiede zu VBA und der VB-Vollversion herausgearbeitet, die geringer sind, als oft vermutet wird. In der Praxis werden viele von Ihnen zwischen den verschiedenen Dialekten wechseln, denn die VB-Vollversion und VBA sind ernstzunehmende Umgebungen für Automationslösungen und auch für das Prototyping von Scripts eine gute Wahl. Sie sollten also die Unterschiede zwischen VB 6.0, VBA und VBS gut kennen. Das gilt auch dann, wenn Sie nur Scripts programmieren wollen, denn Sie werden immer wieder Codebeispiele in VB 6.0 und VBA finden, die Sie in VBS umsetzen möchten.
Die großen Brüder sind beachtenswert
Sprachregelungen in diesem Buch Der Begriff Visual Basic wird in der Fachwelt in Begriffsabgrenzung drei unterschiedlichen Bedeutungen verwendet: 왘 Visual Basic meint eine Programmiersprache. 왘 Visual Basic bezeichnet eine Entwicklungsumgebung im Rahmen von Visual Studio. 왘 Visual Basic dient als Oberbegriff über die VB-Sprachfamilie.
Diese Mehrfachbedeutung macht es schwierig, sich eindeutig auszudrücken. In diesem Buch werden folgende Sprachregelungen verwendet:
151
8 Die Visual Basic-Sprachfamilie
VB VB 6.0
왘 Visual Basic (oder kurz „VB“) wird als Oberbegriff über die Sprachfamilie verwendet. 왘 Die Bezeichnung „VB-Vollversion“ wird für die kompilierungsfähige Programmierspra-
che im Rahmen von Visual Studio verwendet, VB 6.0 für die Version 6.0 der VB-Vollversion. Zur Vereinfachung wird an einigen Stellen VB 6.0 synonym zu „VB-Vollversion“ verwendet. Auf die Kompatibilität zu früheren Versionen wird nicht eingegangen. Grundsätzlich kann allerdings festgehalten werden, dass sich von VB5 zu VB 6.0 an der Sprache selbst nicht viel geändert hat. Der Schritt von VB 6.0 zu VB.NET ist wesentlich größer. VB 6.0/VBA
왘 Das Kürzel VB 6.0/A bedeutet: VB 6.0 und VBA. Dies ist sinnvoll, weil die meisten Aus-
sagen für die VB-Vollversion häufig auch für VBA gelten. VBS Beispiele
왘 Die Ausdrücke Visual Basic Script, VBScript und VBS bezeichnen die Scriptsprache.
Beispiele in diesem Kapitel Die Beispiele in diesem Kapitel wurden in der Regel in VBScript für den Windows Script Host (WSH) geschrieben, weil dieser Scripting Host am einfachsten zu beherrschen ist. Wenn Sie noch keine Erfahrungen mit dem WSH haben, sollten Sie einen Blick in das Kapitel „Scripting Hosts“ werfen. Die Beispiele zu diesem Kapitel finden Sie als WSH-Dateien mit der Erweiterung .vbs auf der Buch-CD [CD:/code/sprachen/vbs/]. Die Beispiele, die nicht in VBS lauffähig sind, finden Sie in einem VB 6.0-Projekt [CD:/code/sprachen/_alle/vb-beispiele.vbp]. Soweit dies auf Grund der Sprachunterschiede möglich ist, ist in dieser Projektdatei auch eine Kopie der VBS-Beispiele enthalten. Die meisten Beispiele sind ohne weiteres auch in VB 6.0/VBA lauffähig, wenn Sie beachten, dass anders als in VBS alle Befehle Teile einer Unterroutine sein müssen. Außerhalb einer Unterroutine dürfen nur Variablen und Typen deklariert werden. Dazu ein Beispiel: ausgabe = "Hallo" MsgBox ausgabe Listing 8.1: Ein VBS-Script für den WSH [helloworld.vbs]
Umsetzung in VB6/VBA
Dieses Script müssen Sie in VB 6.0/VBA in folgenden Code umsetzen und dann die Unterroutine main() starten: Sub main() ausgabe = "Hallo" MsgBox ausgabe End Sub
Jede Programmzeile muss Teil einer Unterroutine sein.
Listing 8.2: Umsetzung des vorherigen Scipt in VB 6.0/VBA Sub Main()
152
Wenn Sie eine VB 6.0-Anwendung starten, wird automatisch das Unterprogramm Sub Main() oder ein in der Projektkonfiguration ausgewähltes Formular aufgerufen. Aus der Entwicklungsumgebung heraus haben Sie die Möglichkeit, die Ausführung auch bei anderen Unterroutinen beginnen zu lassen.
Die Visual Basic-Sprachfamilie
8.1
Die Visual Basic-Sprachfamilie
Visual Basic ist Microsofts Weiterentwicklung der Programmiersprache Basic. Visual Basic ist inzwischen die beliebteste Programmiersprache in der Microsoft-Windows-Welt [CWO99]. Sie zeichnet sich durch das Rapid Application Development (RAD) aus: die Fähigkeit, einfach und schnell Anwendungen zu entwickeln. Basic wurde 1965 entwickelt und ist die Abkürzung für Beginners All Purpose Symbolic Instruction Code. Diese Sprache war bei Computereinsteigern beliebt, unter Profis jedoch auf Grund ihrer mangelnden Strukturiertheit (Stichwort: Goto-Anweisung) verrufen. Microsoft hat Basic mit Visual Basic aus der Schmuddelecke unter den Programmiersprachen geholt und um Konstrukte der Objektorientierung erweitert.
Geschichte
Visual Basic war bis einschließlich Version 6.0 nur eine klassenbasierte, nicht jedoch eine objek- Objektorientorientierte Programmiersprache, da das wesentliche objektorientierte Prinzip der Vererbung tierung nicht vorhanden war (Klassifikation nach Wegner, siehe [WEG89], S. 245ff. und [WEG90]). Visual Basic .NET (VB ab Version 7.0) unterstützt jedoch Vererbung und die darauf aufbauenden Formen des Polymorphismus. Visual Basic bleibt aber weiterhin eine hybride Programmiersprache, da es ähnlich wie in C++ möglich ist, auch rein prozedural zu programmieren. Java und Smalltalk sind dagegen Sprachen aus der Gruppe der reinen objektorientierten Programmiersprachen. Auch wurde ab VB-Version 7.0 (VB.NET) endlich das letzte Einsatzgebiet der Goto-Anweisung eliminiert. Visual Basic hat inzwischen zwei kleine Brüder bekommen: Visual Basic for Applications VBA und VBS (VBA) und Visual Basic Script (VBS oder VBScript). Die folgende Grafik veranschaulicht den Umfang der Sprachdefinition in den verschiedenen VB-Dialekten in verschiedenen Versionen. Bild 8.1: Sprachumfang der VBDialekte
Visual Basic 2007 (Visual Basic 9.0) Visual Basic 2005 (Visual Basic 8.0) Visual Basic .NET 2003 (Visual Basic 7.1) Visual Basic .NET 2002 (Visual Basic 7.0)
Visual Basic 6.0 / VBA 6.3 Visual Basic 5.0 VBA 5.0
Ab Version 7.0 entfallene Befehle VBScript 5.6
Zusätzliche Befehle, die es nur in VBScript gibt
© www.IT-Visions.de 2000-2006
153
8 Die Visual Basic-Sprachfamilie
Die Neugestaltung der Sprache Visual Basic ab Version 7.0 gefällt nicht allen Anwendern. Einige haben im Internet zu einer Petition an Microsoft aufgerufen, das alte Visual Basic 6.0 unter dem Name „VB.COM“ weiterzuentwickeln [ClassicVB01].
8.1.1
Visual Basic for Applications (VBA)
Visual Basic for Applications (VBA) ist eine Interpretersprache zur Automatisierung der Bedienung einer Anwendung und ersetzt in vielen Fällen die früheren Makrosprachen der Anwendungen. Ein VBA-Programm läuft stets innerhalb eines VBA-Host. Dieser ist eine VBA-fähige Anwendung. Vorreiter bei der Integration von VBA in Anwendungen ist Microsoft mit seiner Office-Produktfamilie. Darüber hinaus unterstützen aber auch noch viele andere Anwendungen VBA: 왘 WordPerfect Office 왘 CorelDraw ab Version 왘 AGRESSO 왘 TurboCAD Professional 왘 IntelliCAD 왘 Micrografx iGrafx Professional 왘 Psipenta 왘 Rational Rose
Eine Liste aller VBA-fähigen Produkte findet man unter [VBA01]. VBA in MS Office
In früheren Versionen der Microsoft Office-Produktfamilie hatten die Kernprodukte ihre eigenen Basic-Dialekte: Excel VBA, Word Basic, Access Basic. Mit Microsoft Office 97 erfolgte eine Vereinheitlichung hinsichtlich der Sprachsyntax. Außerdem wurde Powerpoint ebenfalls VBA-fähig. Uneinheitlich blieb jedoch die Entwicklungsumgebung. Die Funktionen der VBA-Entwicklungsumgebung werden im Rahmen der fortgeschrittenen Techniken besprochen.
Interpreta- Grundsätzlich gilt, dass VBA interpretiert wird. Während es in Office 97 keine Möglichkeit tion und gab, VBA zu kompilieren, ist dieser Grundsatz ab Office 2000 in einigen Fällen aufgeweicht Kompilierung
worden. Mit VBA können nun in zwei abgegrenzten Fällen COM-DLLs erstellt werden: zum einen bei der Erstellung von COM-Add-ins, zum anderen bei der Erstellung von so genannten Datenumgebungen.
8.1.2 „Light“Version
Visual Basic Script (VBS)
Visual Basic Script ist eine „Light“-Version von Visual Basic. Bewusstes Entwicklungsziel war es, eine einfache und speicherschonende Interpretersprache zu schaffen. Microsoft nennt Visual Basic Script in Dokumentationen auch häufig Visual Basic Scripting Edition. Gebräuchliche Abkürzungen sind VBScript und VBS. Die Kernunterschiede zu VB 6.0 und VBA sind: 왘 eingeschränkte Fehlerbehandlung 왘 keine Datentypen (daher keine Typisierung)
154
Die Visual Basic-Sprachfamilie
왘 keine direkten Aufrufe von durch DLLs exportierten Funktionen („API-Calls“) 왘 lediglich Unterstützung des späten Bindens via IDispatch bei der Nutzung von COM-
Komponenten 왘 weniger eingebaute Funktionen Allerdings gibt es – wie Abbildung 8.1 darstellt – auch einige Befehle in VBScript, die in anderen Dialekten von VB noch nicht auftreten. Dies sind insbesondere die Schlüsselwörter Execute, Eval, ExecuteGlobal und Class.
Zusätzliche Features
Der erste Einsatzort von Visual Basic Script war der Microsoft Internet Explorer 3.0 als EinsatzMicrosofts Antwort auf das von Netscape entwickelte JavaScript. Dabei sollte VBScript gebiete schon damals zwei Aufgabengebiete abdecken: die Herstellung der Verbindung verschiedener ActiveX-Steuerelemente in Webseiten und die Erledigung kleinerer dynamischer Aufgaben innerhalb des Browsers. Naheliegend war das nächste Einsatzgebiet der Webserver innerhalb der Active Server Pages (ASP). Microsoft erkannte aber bald, dass VBScript mehr Potenzial bietet. Die Darstellung in diesem Buch basiert auf der Version 5.7, die funktional identisch ist mit den Versionen 5.5/5.6 und die sich von Version 5.1 nur um Erweiterungen bei der mitgelieferten Komponente RegExp zur Verarbeitung von regulären Ausdrücken unterscheidet. VBScript-Version
Ausgeliefert mit
1.0
• Internet Explorer 3.0
2.0
• Internet Information Server 3.0
3.0
• • • •
4.0
• Visual Studio 6.0
5.0
• Internet Explorer 5.0
5.1
• Windows 2000
5.5
• Separates Add-on, siehe [MSS00]
5.6
• • • •
5.7
• Windows Vista
Tabelle 8.1: Auslieferung verschiedener VBS-Versionen
Internet Explorer 4.0 Internet Information Server 4.0 Windows Scripting Host 1.0 Outlook 98
Windows XP Windows Server 2003 Internet Explorer 6.0 Teil der WSH 5.6-Erweiterung für Windows NT 4.0/98/ ME/2000, siehe [MSS00]
155
8 Die Visual Basic-Sprachfamilie
Ermittlung der Sprachversion Eingebaute Versionskonstanten
Mit den folgenden Codezeilen können Sie innerhalb eines Script die Versionsnummer von VBScript ermitteln. VBScript stellt dazu vier eingebaute Konstanten bereit. Diese sind in anderen VB-Dialekten allerdings nicht verfügbar. MsgBox "Dies ist die Sprache " & ScriptEngine _ & " Version " & ScriptEngineMajorVersion & _ "." & ScriptEngineMinorVersion & "." & _ ScriptEngineBuildVersion Listing 8.3: Ermittlung der VBS-Version [_Sprachversion.vbs]
8.1.3 eVB
Embedded Visual Basic ist ein Visual Basic-Dialekt zur Entwicklung von Anwendungen für Windows CE. Die Sprache eMbedded Visual Basic hat Microsoft mit der Version 3.0 sterben lassen und empfiehlt die Migration auf Visual Basic .NET, das auch für das .NET Compact Framework für Windows CE/Pocket PC/Windows Mobile verfügbar ist.
8.1.4 .NET
Embedded Visual Basic (eVB)
Visual Basic .NET
Im Zuge von Visual Basic .NET (VB.NET) fusioniert Microsoft die drei Geschwister Visual Basic 6.0, Visual Basic for Applications (VBA) und VBScript zu einer Sprache. VB.NET wird in diesem Buch nicht behandelt. Bitte schauen Sie dazu in [SCH08].
8.1.5
Anwendungsgebiete
Abbildung 8.2 zeigt die Anwendungsgebiete der verschiedenen Visual Basic-Dialekte. Neu in Windows Vista ist der Einsatz von VBScript zur Erstellung von Sidebar Gadgets.
8.2
Grundlagen
Dieses Kapitel beschäftigt sich mit grundlegenden Syntaxregeln und dem Aufbau von Programmen in den verschiedenen VB-Dialekten.
8.2.1 Grundregeln
Grundlegendes zur Syntax
Zu Beginn die wichtigsten Regeln zur Visual Basic-Syntax im Überblick: 왘 Grundsätzlich enthält jede Zeile genau einen Befehl. 왘 Es ist möglich, mehrere Befehle getrennt durch einen Doppelpunkt in eine Zeile zu
schreiben. Von dieser Möglichkeit sollten Sie aber aus Gründen der Übersichtlichkeit keinen Gebrauch machen. 왘 Wenn Befehle sich über mehr als eine Zeile erstrecken sollen, müssen alle Zeilen mit nicht abgeschlossenen Befehlen mit einem Unterstrich „_“ enden. 왘 Leerzeilen, Leerzeichen und Tabulatoren werden ignoriert.
156
Grundlagen
왘 Visual Basic ist nicht case-sensitive: Die Groß- und Kleinschreibung der Schlüsselwörter
ist also ebenso ohne Bedeutung wie die Schreibweise Ihrer selbst gewählten Bezeichner für Variablen, Unterroutinen etc. 왘 Für Bezeichner gibt es folgende Regeln:
Bezeichner
왘 Sie müssen mit einem Buchstaben beginnen. 왘 Sie dürfen nicht länger als 255 Zeichen sein. 왘 Sie dürfen nicht mit Schlüsselwörtern der Sprache identisch sein. 왘 Sie dürfen außer dem Unterstrich keine Satz- oder Sonderzeichen enthalten. 왘 Kommentarzeilen werden mit einem Hochkomma (') eingeleitet. Alternativ können Sie
Kommentare
als Markierung für Kommentare das Schlüsselwort REM verwenden. VBScript
COM-Komponenten (Scriptlets)
VBA
COM-Komponenten
VB (bis 6.0)
Embedded Visual Basic (eVB)
VB.NET (ab 7.0)
Windows DesktopAnwendungen
Windows DesktopAnwendungen
KonsolenAnwendungen
KonsolenAnwendungen
Windows-Dienste
Windows-Dienste
COM-Komponenten
COM-Komponenten
Bild 8.2: Anwendungsgebiete der verschiedenen Visual BasicDialekte
.NET-Komponenten
ASP
IIS-Webclasses
ASP.NET
Visual Studio Tools for Microsoft Office (VSTO)
Office-Makros
Office-Add-ins
Office-Add-ins
Office-Add-ins Anwendungen für Windows CE
Anwendungen für Windows CE
WSH
Internet ExplorerClient Anwendungen
Internet ExplorerClient Anwendungen
Vista Sidebar Gadgets
Exchange Server Event Agent
SQL Server Agent
DTS-Transformationen
SQL Server Stored Procedures + UDTs Andere Active Scripting-Hosts
(C) www.IT-Visions.de 2002-2006
157
8 Die Visual Basic-Sprachfamilie
8.2.2
Speicherung des Programmcodes
Module und Projekte
In VB 6.0/VBA wird Visual Basic Code in Modulen (bzw. Forms und Klassenmodulen) angeordnet, wobei jedes Modul entweder in einer eigenen Datei (VB 6.0) gespeichert wird oder alle Module in einer Dokumentdatei (VBA). Bei VB 6.0 gibt es zusätzlich eine Projektdatei, die die Information enthält, welche Moduldateien zum Projekt gehören. In VBA hält die Dokumentendatei die einzelnen Moduldateien zusammen.
Scripts
In Zusammenhang mit VBS sind die Begriffe Modul und Projekt nicht gebräuchlich. Vielmehr spricht man von Scripts. Ein Script entspricht in etwa einem Modul. Die Anordnung und Speicherung der Scripts ist stark vom Scripting Host abhängig: In einigen Fällen sind die Scripts in eigenständigen Dateien abgelegt (z.B. beim Windows Scripting Host), in anderen Fällen sind sie nur Mitbewohner in anderen Dateien (z.B. ASP, DHTML). In einigen Umgebungen können Scripts andere Scripts einbinden, um Scriptcode wiederzuverwenden.
8.2.3
Startpunkt eines Programms
Programm- Die verschiedenen VB-Dialekte unterscheiden sich auch darin, wo ein Programm startet: start
왘 In VB 6.0/VBA muss jede Zeile Programmcode Teil einer Unterroutine sein. Beim Auf-
ruf des Programms in VB 6.0 wird die Ausführung mit der Unterroutine begonnen, die Sub Main() heißt. Alternativ dazu kann die Ausführung in VB 6.0 auch mit dem Start eines Formulars beginnen. 왘 In VBA ist die Ausführung komplett ereignisbasiert. Sie beginnt mit der Ereignisbehandlungsroutine, deren Ereignis zuerst getriggert wird. Manuell kann jede beliebige Unterroutine gestartet werden. 왘 In VBS kann es Programmcode geben, der nicht Teil einer Unterroutine ist. In Abhängigkeit vom Scripting Host gibt es zwei Möglichkeiten zum Start: 왘 Üblicherweise beginnt die Ausführung bei der ersten Programmzeile, die nicht Teil
einer Unterroutine ist. 왘 Einige Scripting Hosts arbeiten jedoch ausschließlich ereignisgesteuert und starten
das Script mit einer bestimmten Ereignisbehandlungsroutine.
8.3 Hello World
158
Einfache Ein- und Ausgabefunktionen
Wenn man sich neu mit einer Programmiersprache beschäftigt, dann interessieren zunächst nicht die mächtigen Sprachkonstrukte, sondern eine ganz einfache Funktion: Wie kann ich eine Ausgabe machen? Das erste Programm heißt dann traditionell „Hello World“ und steht daher auch hier am Anfang. Nach der Erläuterung der Funktion MsgBox() folgt die Beschreibung der Funktion InputBox().
Einfache Ein- und Ausgabefunktionen
Bitte beachten Sie, dass nicht alle Scripting Hosts die Ausführung von MsgBox() und InputBox() zulassen: Serverseitige Scripts, die unbeaufsichtigt laufen, sollten keine Dialogfenster ausgeben und auf keinen Fall modale Dialogfenster, die darauf warten, dass ein nicht vorhandener Benutzer sie wegklickt. Es gibt auch serverseitige Scripting Hosts (z.B. SQL Server Agent Job Scripting), die bei Verwendung von MsgBox() und InputBox() leider nicht protestieren. Sie laufen leicht in die Falle, dass Ihr Script „hängt“, weil niemand das Dialogfenster beenden kann. MsgBox() und InputBox() werden in den folgenden Beispielen zur Vorstellung der einzelnen Sprachkonstrukte immer wieder gute Dienste leisten.
8.3.1
Ausgaben mit MsgBox()
Die einfachste Ausgabeprozedur, die in allen Visual Basic-Dialekten zur Verfügung steht, MsgBox() heißt MsgBox(). MsgBox "Hello World" Listing 8.4: Ihr erstes VB-Programm
Die Ausgabe erfolgt in einem einfachen Dialogfenster. MsgBox() hat weitere Parameter, mit denen das Aussehen der Ausgabe beeinflusst werden kann. MsgBox text[,buttons][,titel]
Erforderlich ist nur der eigentliche Dialogfenstertext. Mit Hilfe des Parameters Buttons können Buttons die darzustellenden Schaltflächen und das das Dialogfenster zierende Symbol festgelegt werden. Für Buttons kann ein Wert angegeben werden, der sich aus der Addition von mehreren Werten aus Tabelle 8.2 und Tabelle 8.3 ergibt. Zusätzlich kann die Konstante 4096 (vbSystem Modal) hinzuaddiert werden. Dadurch steht das Meldungsfenster immer im Vordergrund. Wert
Symbolische Konstante
Bedeutung
0
vbOKOnly
1
vbOKCancel
+
2
vbAbortRetryIgnore
+ +
3
vbYesNoCancel
+ +
4
vbYesNo
+
5
vbRetryCancel
+
Wert
Konstante
Symbol
16
vbCritical
Rotes Kreuz
32
vbQuestion
Fragezeichen
48
vbExclamation
Ausrufezeichen in gelbem Dreieck
64
vbInformation
Normales Ausrufezeichen
Tabelle 8.2: Konstanten für MsgBox()Schaltflächen
Tabelle 8.3: Konstanten für die MsgBox()Symbole
159
8 Die Visual Basic-Sprachfamilie
Sprache
Rückgabewerte
Die Sprache, in der die Schaltflächen beschriftet werden, hängt immer von der Sprachversion des Betriebssystems ab. So werden Sie auf einem englischen Betriebssystem immer „Cancel“ statt „Abbrechen“ lesen müssen, auch wenn Sie einen deutschen Text ausgeben wollen. Wenn MsgBox() mit mehr als nur einer Schaltfläche dargestellt wurde, interessiert es natürlich, welche Schaltfläche der Anwender gewählt hat. Dafür steht MsgBox() auch noch in einer Variante als Funktion mit Rückgabewert zur Verfügung. antwort = MsgBox(text[,buttons][,titel])
Bitte beachten Sie dabei die Verwendung der Klammern im Gegensatz zur Verwendung von MsgBox() ohne Rückgabewert. Diese Spitzfindigkeit wird später näher erläutert. Es gibt für jeden der sieben Schaltflächentypen einen Rückgabewert (siehe folgende Tabelle). Tabelle 8.4: Konstanten für die MsgBox()Rückgabewerte
Wert
Konstante
Gewählte Schaltfläche
1
vbOK
OK
2
vbCancel
Abbrechen
3
vbAbort
Beenden
4
vbRetry
Wiederholen
5
vbIgnore
Ignorieren
6
vbYes
Ja
7
vbNo
Nein
„Hello World“ in einer verbesserten Version könnte dann folgendermaßen aussehen: antwort = MsgBox("Macht Ihnen das Lesen dieses Buches Spaß?",_ vbYesNo + vbQuestion, "Hallo Leser") MsgBox "Die Antwort war: " & antwort Listing 8.5: „Hello World“ mit Antwort
8.3.2 InputBox()
Eingaben mit InputBox() empfangen
Wenn das Klicken auf eine von sieben verschiedenen Schaltflächen als Antwort des Benutzers nicht reicht, können Sie auf die eingebaute InputBox()-Funktion zurückgreifen und erhalten ein Dialogfenster mit Eingabezeile. antwort = InputBox(text[,titel][,vorgabewert])
Pflicht ist die Angabe des Fragetextes. Optional sind Dialogfenstertitel und Vorgabewerte für die Eingabezeile. antwort = InputBox("Wie heißen Sie?", _ "Wichtige Frage", "Holger Schwichtenberg") MsgBox "Sie heißen " & antwort Listing 8.6: InputBox mit Vorgabewert [hello_world_3.vbs]
160
Variablen
Bild 8.3: InputBox mit
Vorgabewert
8.4
Variablen
Variablennamen unterliegen den erwähnten Regeln für Bezeichner. Es ist in keinem der VB- Variablen Dialekte Pflicht, Variablen zu deklarieren. Im Standardmodus ist die Deklaration optional. Sie erfolgt mit dem Schlüsselwort DIM, gefolgt vom Namen der Variablen. Weitere Variablen können durch Kommata abgetrennt werden. DIM a DIM name,vorname,strasse,ort
Jedoch kann der Programmierer sich selbst die Pflicht auferlegen, alle Variablen deklarieren Option zu müssen. Dazu dient die Anweisung Option Explicit, die zu Beginn eines jeden Code- Explicit Moduls bzw. Script stehen muss. Nach einem Option Explicit führt jeder Zugriff auf eine nicht deklarierte Variable zu einem Fehler. Option Explicit Dim a Dim b a = 1 b = 2 ' Fehler: c nicht deklariert! c = b + a Listing 8.7: Verwendung von Option Explicit [explicitDemo.vbs]
Ohne die Verwendung von Option Explicit kann es leicht zu schweren Fehlern kommen. Im folgenden Beispiel führt ein Tippfehler (vergessenes t bei start) dazu, dass VB 1000 minus 0 statt 1000 minus 500 errechnet. start = 500 Hier fehlt ein "t". ende = 1000 dauer = ende – sart MsgBox ende & " – " & start & " = " & dauer Listing 8.8: Ein Tippfehler kann schwere Folgen haben.
8.4.1
Gültigkeitsbereich von Variablen
Visual Basic kennt drei unterschiedliche Gültigkeitsbereiche (engl. Scope) von Variablen:
Scope
왘 Lokale (prozedurweite) Variablen gelten nur in einer Unterroutine. 왘 Modul-globale (modulweite) Variablen gelten in allen Unterroutinen eines Moduls. 왘 Globale (programmweite) Variablen gelten in allen Modulen eines Projekts.
161
8 Die Visual Basic-Sprachfamilie
Dies ist die Sichtweise von VB 6.0/VBA. In VBS laufen die Uhren – wie so oft – etwas anders: 왘 Da VBS keine Module kennt, sind alle globalen Variablen auch programmweite Variablen. 왘 Da in VBS Programmcode außerhalb von Unterroutinen existieren darf, besitzt das
Hauptprogramm keine eigenen lokalen Variablen. Alle lokalen Variablen des Hauptprogramms sind globale Variablen. Überlappung Für alle VB-Dialekte gilt jedoch, dass lokale Variablen in Unterroutinen den gleichen von Variab- Namen haben dürfen wie globale Variablen oder lokale Variablen in anderen Unterroutilendeklarationen nen. Lokale Variablen überlagern globale Variablen, ohne diese zu beschädigen. Wenn also
eine globale Variable x existiert und in einer Unterroutine eine lokale Variable x deklariert wird, so ist das globale x von dem lokalen x verdeckt. Jeder Zugriff auf x ist ein lokaler Zugriff. Nach dem Verlassen der Routine hat das globale x den gleichen Wert wie vorher. Public und Private
Visual Basic Script kennt ebenso wie die anderen VB-Dialekte die Einschränkung des Gültigkeitsbereichs mit den Schlüsselwörtern Private und Public. Dabei treten diese Schlüsselwörter an die Stelle des Dim. Allerdings hat die Einschränkung auf Private in den meisten Scripting Hosts keine Bedeutung, da es in der Regel nur ein Script in einer Datei gibt. Innerhalb eines Script sind ebenso wie in VB 6.0/VBA innerhalb eines Moduls alle Variablen öffentlich.
8.4.2
Benennung von Variablen
Ungarische Gemäß der ungarischen Notation gibt es in Visual Basic einen Vorschlag zur Benennung von Notation Variablen anhand des Datentyps. Dabei steht jeweils zu Beginn des Variablennamens in
Kleinschrift ein dreibuchstabiges Präfix. Tabelle 8.5: Vorschläge für Variablennamen gemäß ungarischer Notation
162
(Unter-)Typ
Präfix
Beispiel
Boolean
bln
blnAktiviert
Byte
byt
bytAlter
Date
dtm
dtmGeburtstag
Double
dbl
dblUmsatz
Integer
int
intEinwohnerzahl
Long
lng
lngEinwohnerzahl
Single
sng
sngUmsatz
String
str
strBuchtitel
Object
obj
objBenutzer
Datentypen
8.5
Datentypen
Ein wichtiges Kriterium für eine Programmiersprache ist der Grad der Typisierung. Er gibt Typisierungsan, inwieweit eine Variable an einen Datentyp gebunden wird und wie streng der Compiler grad oder Interpreter der Sprache es mit Zuweisungen an solche Variablen hält, die nicht dem zugewiesenen Datentyp entsprechen.
8.5.1
Datentypen in VBS
Visual Basic Script ist eine sehr schwach typisierte Sprache: Es gibt in VBScript nur einen Schwache Datentyp mit Namen Variant, der alle möglichen Arten von Daten aufnehmen kann. Ein Typisierung in VBS und dieselbe Variable kann während des Programmablaufs Daten unterschiedlichen Typs speichern. Je nach dem aktuellen Inhalt wird die Variable jedoch einem von zwölf so genannten Subtypen zugeordnet. (Unter-)Typ
Beschreibung
Symbolische Typkonstante
TypID
Boolean
Wahrheitswert; True oder False
vbBoolean
11
Byte
Ganzzahl (8 Bit); 0 bis 255
vbByte
17
Integer
Ganzzahl (16 Bit); –32.768 bis 32.767
vbInteger
2
Currency
Fließkommazahl; –922.337.203.685.477,5808 bis 922.337.203.685.477,5807
vbCurrency
3
Long
Ganzzahl (32 Bit); –2.147.483.648 bis 2.147.483.647
vbLong
4
Single
Fließkommazahl; –3,402823E38 bis –1,401298E–45 für negative Werte und von 1,401298E–45 bis 3,402823E38 für positive Werte
vbSingle
5
Double
Fließkommazahl; 1,79769313486232E308 bis –4,94065645841247E–324 für negative Werte und von 4,94065645841247E–324 bis 1.79769313486232E308 für positive Werte
vbDouble
6
Date
Datums- und Uhrzeitangaben; Speicherung in Form einer Fließkommazahl, die die Anzahl der Tage relativ zum 31.12.1899 angibt. Durch negative Werte können auch Daten vor diesem Bezugspunkt angegeben werden.
vbDate
7
String
Zeichenfolge mit variabler Länge
vbString
8
Object
Zeiger auf ein Objekt
vbObject
9
Variant
Kann einen beliebigen Wert aufnehmen
vbVariant
12
Tabelle 8.6: Datentypen in VB 6.0/VBA bzw. Subtypen in VBS
163
8 Die Visual Basic-Sprachfamilie
Typinformationen
Informationen über den aktuellen Subtyp Mit den Funktionen TypeName(varname) und VarType(varname) kann ermittelt werden, welchen Subtyp eine Variable oder ein Wert aktuell hat. Während TypeName() den Namen des Datentyps als Zeichenkette liefert, gibt VarType() eine Typkonstante (vgl. Tabelle 8.6) zurück. x = 2000 MsgBox typename(x) & "," & VarType(x) ' liefert Integer, 2 x = "Holger Schwichtenberg" MsgBox typename(x) & "," & VarType(x) ' liefert String, 8 x = #8/1/1972# MsgBox typename(x) & "," & VarType(x) ' liefert Date, 7 MsgBox typename("1.8.72") ' liefert String MsgBox typename(1234.56) ' liefert Double Listing 8.9: Ermittlung des Datentyps einer Variablen [Datentypen1.vbs]
Für einzelne Datentypen kann auch mit Hilfe spezieller Funktionen direkt geprüft werden, ob eine Variable einen bestimmten Wertetyp enthält: 왘 isNumeric(varname) 왘 isDate(varname)
8.5.2
Datentypen in VB 6.0/VBA
Starke Einer der wesentlichen Unterschiede von VB 6.0/VBA zu VBS ist die Möglichkeit, Variablen Typisierung in explizit einem Datentyp zuzuweisen. Damit kann der Programmierer eine strenge (obschon VB 6.0/ VBA
im Vergleich zu anderen Sprachen wie C/C++ und Java immer noch lockere) Form der Typisierung erreichen.
Typkonvertierung
Wenn einer Variablen ein Typ zugewiesen wurde, dann kann diese Variable innerhalb ihres Gültigkeitszeitraums nur Werte des vorgegebenen Typs aufnehmen. Eine Missachtung führt zu einem Laufzeitfehler. Allerdings wird bei der Zuweisung von Variablen bzw. Werten unterschiedlichen Typs keine Fehlermeldung generiert, sondern eine automatische Typkonvertierung durchgeführt.
Schlüssel- Eine Typangabe erfolgt mit dem Schlüsselwort As im Rahmen einer Variablendeklaration. wort „As“ Da VBS keine Typisierung kennt, führt jegliche Verwendung des Schlüsselworts As in VBS
zu einem Fehler! Dim Dim Dim Dim
s x z c
As As As As
String Integer Long Currency
Wählbarer In VB 6.0/VBA gibt es aber auch den Datentyp Variant, der genauso flexibel ist wie Variant Typisierungs- aus VBS. Die strengere Typisierung ist eine Option in VB 6.0/VBA, von der viele Entwickler grad
gerne Gebrauch machen, um den Programmcode übersichtlicher und robuster zu gestalten. In VB 6.0/VBA gibt es drei Möglichkeiten, eine Variable vom Typ Variant zu erhalten: 왘 Die Variable wird gar nicht deklariert. 왘 Die Variable wird nur mit DIM varname deklariert. 왘 Die Variable wird mit DIM varname As Variant deklariert.
164
Datentypen
Eine beliebte Falle bei VB-Anfängern ist die Deklaration von mehreren Variablen in einer Zeile. Dabei muss zu jeder Variablen der Datentyp einzeln angegeben werden! ' In dieser Zeile sind a und b Variants! Dim a, b, c As Integer ' Nur so sind alle drei Integer! Dim a As Integer, b As Integer, c As Integer
Definition eigener Datentypen Eigene, zusammengesetzte Datentypen (in anderen Type Sprachen „Strukturen“ genannt) können in VBA und VB 6.0 mit Type...End Type definiert werden. Diese Möglichkeit gibt es in VBS nicht, da dafür eine stärkere Typisierung der Sprache notwendig ist. Type Person Name As String Geb As Date Kinderanzahl As Byte Verheiratet As Boolean End Type ' === Nutzung eines eigenen Datentyps Sub EigenerTyp() Dim HS As Person HS.Name = "Holger Schwichtenberg" HS.Geb = #8/1/1972# HS.Kinderanzahl = 0 HS.Verheiratet = False MsgBox HS.Name & Chr(13) & _ "ist am " & HS.Geb & " geboren," & Chr(13) & _ "ist " & IIf(Not HS.Verheiratet, "nicht ", "") & _ "verheiratet " & Chr(13) & _ "und hat " & HS.Kinderanzahl & " Kinder!" End Sub Listing 8.10: Definition und Nutzung eines eigenen Datentyps Bild 8.4: Ausgabe des obigen Beispiels
Zusammengesetzte Typen können wie jeder elementare Datentyp zum Aufbau von Arrays oder zur Übergabe an Unterroutinen verwendet werden.
165
8 Die Visual Basic-Sprachfamilie
Den Unterschied zwischen einem Typ und einer Klasse (Klassen werden später behandelt) zeigt die folgende Tabelle. Tabelle 8.7: Typ versus Klasse
Eigenschaft
Typ
Klasse
Öffentliche Mitglieder
Ja
Ja
Private Mitglieder
Nein
Ja
Methoden
Nein
Ja
Ereignisse
Nein
Ja
Instanziierung
Wie elementarer Datentyp
Mit New-Operator
Möglich in VBS
Nein
Ja
Möglich in VB 6.0
Ja
Ja
Möglich in VBA
Ja
Ja
8.5.3
Startwerte von Variablen
Startwerte Visual Basic belegt Variablen automatisch mit einem Startwert. Eine typisierte Variable hat
zu Beginn den jeweiligen Grundwert des Typs (0, Leerzeichenkette oder 00:00:00). Empty
Für Variant-Variablen kennt VB einen besonderen Startzustand: Empty. Empty bedeutet, dass eine Variant-Variable noch nicht mit einem Wert belegt wurde. Ob eine VariantVariable bereits belegt wurde, kann mit isempty (variablenname) überprüft werden. Der Zustand Empty kann einer Variant-Variablen aber auch nach Gebrauch wieder explizit zugewiesen werden. Eine Variable im Zustand Empty, die in einem Ausdruck verwendet wird, nimmt dort den Wert 0 oder Leerzeichenkette an, jeweils passend zu dem Ausdruck. MsgBox typename(x) ' liefert Empty If IsEmpty(y) Then MsgBox "y ist Empty!" MsgBox x ' liefert Leerzeichenkette MsgBox x + 5 ' liefert 5 If x = 0 Then MsgBox "x ist 0" ' liefert 5 If x = "" Then MsgBox "x ist Leerzeichenkette" ' liefert 5 x = 5 ' liefert Integer MsgBox typename(x) x = Empty MsgBox typename(x) ' liefert Empty Listing 8.11: Beispiel für den Wert Empty [datentypen2.vbs]
8.6 Literale und symbolische Konstanten
Darstellung von Werten
Statische Werte können in Visual Basic in zwei Formen vorkommen: 왘 Als Literale, also als direkte Angabe von Werten innerhalb eines Ausdrucks
Beispiel: MsgBox "Sie heißen:" & Name Hier ist die Zeichenkette „Sie heißen:“ ein Literal.
166
Darstellung von Werten
왘 Als symbolische Konstanten, die Literale repräsentieren
Beispiel: Const AUSGABE = "Sie heißen: " MsgBox AUSGABE & Name.
Hier ist AUSGABE eine symbolische Konstante für das Literal „Sie heißen: “.
8.6.1
Literale
Literale sind alle statischen Werte, die direkt im Programmcode hinterlegt, also nicht in Variablen oder symbolischen Konstanten (siehe nächstes Kapitel) gespeichert sind. In Visual Basic werden Literale wie folgt dargestellt: 왘 Ganzzahlige numerische Werte werden einfach durch die Aneinanderreihung von Ziffern
Zahlen
dargestellt. 왘 Bei Fließkommazahlen (nichtganzzahlige numerische Werte) wird das Dezimaltrennzeichen nicht durch ein Komma dargestellt, sondern – amerikanisch – durch einen Punkt. 왘 Hexadezimalzahlen werden durch ein vorangestelltes &h, Oktalzahlen durch ein &o
kenntlich gemacht. 왘 Begrenzer für Zeichenketten ist das doppelte Anführungszeichen. Zeichenketten inner-
Andere Zahlensysteme Zeichen-
halb von Zeichenketten können durch zweifache doppelte Anführungszeichen dargestellt ketten werden. 왘 MsgBox "Hallo" 왘 Execute "MsgBox ""Hallo"""
Manche Umgebungen (z.B. HTML) und Komponenten (z.B. WMI) erlauben auch einfache Anführungszeichen als Alternative zu den unübersichtlichen zweifachen doppelten Anführungszeichen. 왘 Der Sonderzustand „Variable ist leer“ wird durch das Wort Empty angezeigt, der Son-
Empty und
derzustand „Variable hat keinen gültigen Wert“ durch das Wort Null. Null kann ebenso Null wie Empty nur Variant-Variablen zugewiesen werden. Zur Überprüfung auf diese Werte sollte nicht das Gleichheitszeichen verwendet werden, sondern die eingebauten Funktionen isNull() und isEmpty(). Sofern eine VariantVariable die Werte Empty oder Null enthält, werden als Typen „Empty“ (vbEmpty = 0) oder „Null“ (vbNull = 1) zurückgeliefert.
왘 Datums- und Uhrzeitangaben werden mit dem Nummerzeichen (#) begrenzt und sind
im amerikanischen Stil anzugeben (siehe Tabelle 8.10).
Datum und Uhrzeit
왘 Boolesche Werte (also die Wahrheitswerte wahr und falsch) werden durch die Konstan-
True und
왘 VB sieht auch explizit einen Wertetyp für Währungen vor, die sich nach der jeweiligen
Währungs-
ten True und False repräsentiert. Aber Achtung: Die Konstante True steht nicht – wie False man vermuten könnte – für den Wert 1, sondern für -1. Zum Glück ist False wenigstens 0. 0 und -1 können alternativ zu den Konstanten True und False verwendet werden. Ländereinstellung des Systems richten. In Deutschland besteht ein gültiger Wäh- angaben
167
8 Die Visual Basic-Sprachfamilie
rungstyp aus einer Fließkommazahl mit nachgestelltem Währungssymbol €. Dabei ist das Dezimaltrennzeichen ein Komma und zusätzlich ist als Tausendertrennzeichen ein Punkt erlaubt. Das Ganze wird wie eine Zeichenkette in Hochkommata gesetzt. Auf Grund der Abhängigkeit von den Systemeinstellungen sollten Sie den Datentyp Currency (Währung) nicht verwenden. Sie können auch intern mit Fließkommazahlen arbeiten und dann für die Ausgabe das Währungssymbol anhängen bzw. eine der eingebauten Formatierungsfunktionen von VB nutzen. Tabelle 8.8: Darstellung von Literalen in VB
Wertetyp
Beispiel
Ganzzahlige Zahl
1234
Fließkommazahl
1234.5678
Hexadezimalzahl
&h0AE1 (entspricht 2785)
Oktalzahl
&o77 (entspricht 63)
Zeichenkette (String)
"Holger Schwichtenberg"
Datum und/oder Uhrzeit
#8/1/1972# #2:30:00 PM# #12/30/1999 1:20:00 AM#
Wahrheitswerte
True, False, -1, 0
Währung
"22345,80 DM"
Sonderzustände
Null, Empty
8.6.2 Const
Symbolische Konstanten
Literale, die in einem Programm mehrfach vorkommen, sollten in Form von symbolischen Konstanten (auch benannte Konstanten genannt) definiert werden, so dass man sie an einem zentralen Ort ändern kann. Dazu dient in allen VB-Dialekten das Schlüsselwort const. Const KonstantenName = Wert
Danach kann eine Konstante wie eine Variable verwendet werden, aber nur lesend. Eine Veränderung ist nicht gestattet. In VB 6.0/VBA kann in der Konstantendefinition als Wert auch ein Ausdruck angegeben werden. VBS unterstützt nur Literale. Symbolische Konstanten sollten Sie immer dann anwenden, wenn Werte entweder wiederholt verwendet werden oder aber besonders lang sind. Sie erhöhen mit symbolischen Konstanten die Verständlichkeit und Wartbarkeit Ihrer Scripts. Mit der gleichzeitigen Erzwingung der Variablendeklaration mit Option Explicit vermeiden Sie Fehler, da falsch geschriebene symbolische Konstanten dem Sprachinterpreter auffallen – Literale werden dagegen nicht überprüft.
168
Darstellung von Werten
Enum VB 6.0/VBA unterstützen die Definition von Aufzählungstypen (Enumerationen). AufzähDazu dient das Schlüsselwort Enum. Enum definiert Aufzählungstypen mit n Konstanten. lungstypem Das Schlüsselwort wird in VBScript nicht unterstützt. [Public | Private] Enum LISTENNAME NAME [= WERT] NAME [= WERT] . . . End Enum
Die Angabe eines Werts für die einzelnen Konstanten ist optional. Ohne diese Angabe werden die Konstanten automatisch mit fortlaufenden Zahlen belegt, wobei die erste Zahl 0 ist. Das erste Beispiel zeigt die Definition von Aufzählungstypen mit expliziten Werten.
Beispiel 1
Enum MitarbeiterTypen Professor = 3 Wissenschaftlicher Mitarbeiter = 2 StudentischeHilfskraft = 1 Sonstiger = 0 End Enum
Erlaubt sind nur Werte vom Typ Long, keine Zeichenketten oder Datumsangaben. Im zweiten Beispiel werden keine Werte explizit genannt. Gelb erhält daher den Wert 0, Beispiel 2 schwarz den Wert 3. Enum GrundFarben gelb rot gruen schwarz End Enum
Beide Formen können gemischt werden. Visual Basic zählt nach einer expliziten Wertzuwei- Beispiel 3 sung von dem Wert aus weiter hoch. Grau ist also 0, rosa 101 und orange 102. Enum AndereFarben grau lila = 100 rosa orange End Enum
Die folgende VB 6.0-Unterroutine zeigt die Anwendung der Aufzählungstypen:
Verwendung
왘 Die Aufzählungstypen sind ein Datentyp, der zur Deklaration von Variablen verwendet
werden kann. 왘 Die einzelnen Konstanten der Aufzählungstypen können an beliebiger Stelle verwendet
werden.
169
8 Die Visual Basic-Sprachfamilie
왘 Den mit dem Namen eines Aufzählungstyps typisierten Variablen kann auch direkt eine
Zahl zugewiesen werden, auch eine Zahl, die nicht in den Aufzählungstypen vorkommt. Sub teste_enum() Dim dieserMitarbeiter As MitarbeiterTypen ' --- Zuweisung mit Konstantennamen dieserMitarbeiter = Professor ' --- Zuweisung mit Wert Führt nicht zum Fehler! dieserMitarbeiter = 3 ' --- Zuweisung mit Wert ' außerhalb der Konstantenliste dieserMitarbeiter = 9 ' --- Verwendung If dieserMitarbeiter StudentischeHilfskraft Then_ MsgBox "Keine studentische Hilfskraft!" MsgBox gruen ' ergibt 2 MsgBox orange ' ergibt 102 End Sub Listing 8.12: Verwendung von mit „Enum“ definierten Aufzählungstypen [modEnum.bas] Vordefinierte Vordefinierte Konstanten Alle VB-Dialekte kennen eine Reihe von vordefinierten Konstanten symbolischen Konstanten, beispielsweise die Konstanten für die MsgBox()-Funktion oder
die Datentypkonstanten. Auf diese Konstanten kann ohne weitere Definition zugegriffen werden. Je nach Umgebung gibt es verschiedene Möglichkeiten, weitere Konstanten verfügbar zu machen: 왘 Immer besteht die Möglichkeit, Konstantendefinitionen mit dem Schlüsselwort const
in den Quelltext zu übernehmen. 왘 Scripting Hosts ermöglichen die Einbindung externer Quellcodedateien, die Konstan-
tendefinitionen enthalten können. Gegenüber der ersten Möglichkeit entfällt die Doppelspeicherung der Konstantendefinitionen. 왘 Entwicklungsumgebungen wie die von VB 6.0/VBA, aber auch einige Scripting Hosts (z.B. WSH ab Version 2.0) gestatten die Einbindung von Typbibliotheken. Dadurch stehen die dort in Konstantenlisten definierten symbolischen Konstanten zur Verfügung.
170
Operatoren
8.7
Operatoren
Die nachfolgende Tabelle zeigt die wichtigsten Visual Basic-Operatoren. Eine Erläuterung Operatoren der Operatoren auf Objektvariablen finden Sie in Kapitel 8.14.6. Zweck
VB-Dialekte
Verfügbare Operatoren
Wertzuweisung unter elementaren Datentypen
VBS/VBA/VB 6.0
A = B
Tabelle 8.9: Operatoren in VB
oder Let A = B
Zuweisungen von Objektvariablen
VBS/VBA/VB 6.0
Set Obj1 = Obj2
Grundrechenarten
alle
+ (Addition) - (Subtraktion) * (Multiplikation) / (Division)
Potenzierung
alle
^
Division ganzzahlig
alle
\
Divisionsrest
alle
mod
Vergleich unter elementaren Datentypen
alle
= < = >
Vergleich von Objektvariablen
alle
Obj1 is Obj2 Obj1 is Nothing
Logische Operatoren
VBS/VBA/VB 6.0
and or not xor eqv imp
Bitweise Operatoren
VBS/VBA/VB 6.0
and or not xor
Zeichenverkettung
alle
&
(Zeichenverkettung ist auch mit dem Pluszeichen möglich, sollte aber nicht verwendet werden!)
Rechenoperationen sind sowohl mit Währungs- als auch mit Datumsangaben möglich. Bei Rechnen den Datumsangaben ist die Grundeinheit immer ein Tag. Um beispielsweise die Datums- mit Datumsangaben angabe um eine Stunde zu erhöhen, müssen Sie 1/24 addieren. Die folgende Tabelle zeigt einige Beispiele. Für die Arbeit mit Datumsangaben gibt es jedoch auch einfachere Datums-/ Uhrzeitfunktionen (siehe Anhang C).
171
8 Die Visual Basic-Sprachfamilie
Tabelle 8.10: Berechnungen mit Datumsund Währungswerten
Berechnung
Ergebnis
#5/1/2000 6:49:00 PM# + 1
02.05.00 18:49:00
#5/1/2000 6:49:00 PM# – 1 / 24
01.05.00 17:49:00
#5/1/2000 6:49:00 PM# + (1 / 24 / 60) * 50
01.05.00 19:39:00
"1234,56 DM" – 100
1134,56
"10,10 DM" * "20 DM"
202
Vollständige Auswertung In VBS/VB 6.0/VBA wird jeder Teilausdruck in einem logischen Ausdruck ausgewertet, auch wenn das Ergebnis durch einen vorherigen Teilausdruck bereits feststeht. Die folgenden Codebeispiele würden in VBS/VB 6.0/VBA mit einem „Division durch 0“-Fehler (Fehlernummer 11) abbrechen. Sub short_circuit_demo1() Führt zum „Division Dim a, b durch 0“-Fehler. a = 1 b = 0 If b = 0 Or a / b > 1 Then MsgBox "Bedingung erfüllt!" End Sub Listing 8.13: [short_circuit_demo1.wsf] Beispiel 2
Das zweite Beispiel zeigt dies mit einer AND-Verknüpfung. Hier werden unter VB 6.0/VBA/ VBS beide Teilausdrücke ausgewertet, obwohl der erste (x 0) bereits falsch ist. Folge ist ein „Division durch 0“-Fehler beim Ausdruck y / x > 0. Sub short_circuit_demo2() Dim x ' As Integer Dim y ' As Integer x = 0 y = 5 If (x 0) And y / x > 0 Then say ("Richtig!") Else say ("Falsch") End If End Sub
Führt zum „Division durch 0“-Fehler.
Listing 8.14: [short_circuit_demo2.wsf] Gleichheitszeichen
172
Doppeldeutiges Gleichheitszeichen Das Gleichheitszeichen hat, wie in vielen anderen Sprachen auch, eine Doppelfunktion als Zuweisungs- und Vergleichsoperator. Einige Sprachen (z.B. C, C++, Java) trennen diese beiden Operatoren jedoch sauber, indem sie ein einfaches Gleichheitszeichen als Zuweisungsoperator und ein doppeltes Gleichheitszeichen (==) als Vergleichsoperator nutzen.
Typkonvertierung
Zu den Aufgaben, die der Autor in seinen Schulungen am liebsten stellt, gehört das folgende Beispiel:
Kleines Rätsel
a = 5 b = 6 c = a = b MsgBox c
Welcher Wert wird hier ausgegeben? Nun, für c wird der Wert False bzw. 0 ausgegeben. Überrascht? Hatten Sie vermutet, c wäre 6? Dass dies falsch ist, liegt daran, dass VB nur das erste Gleichheitszeichen einer Anweisung als Zuweisungsoperator interpretiert. Das zweite Gleichheitszeichen ist ein Vergleichsoperator. c wird also das Ergebnis des Vergleichs von a mit b zugewiesen. Da a und b verschiedene Werte haben, ist c also False.
8.8
Typkonvertierung
Visual Basic besitzt eine implizite Datentypkonvertierung, die viele „unsaubere“ Anweisun- Implizite gen erlaubt, die in anderen Sprachen verpönt sind. Es ist unter VB-Programmierern an vie- Typkonvertierung len Stellen jedoch Usus, die implizite Typkonvertierung zu nutzen, anstatt die Werte vorher mit einer der eingebauten Konvertierungsfunktionen umzuwandeln. Dim s, d, a s = "Holger Schwichtenberg" d = #8/1/1972# a = 28 ausgabe = s & " ist am " & d & _ " geboren und daher jetzt " & a & " Jahre alt!" MsgBox ausgabe Listing 8.15: Beispiel zur impliziten Typkonvertierung
Die Verkettung von Zeichenkettenvariablen, Zeichenkonstanten, Datumsangaben und Zahlen Explizite funktioniert problemlos. Dabei wäre es besser gewesen, die Konvertierung von Datums- und Typkonvertierung Zahlenwerten explizit mit der Funktion CStr() vorzunehmen: ausgabe = s & " ist am " & CStr(d) & _ " geboren und daher jetzt " & _ CStr(a) & " Jahre alt!" Listing 8.16: Beispiel zur expliziten Typkonvertierung [typkonv_1.vbs]
Während das vorherige Beispiel ja vielleicht gerade noch hinnehmbar gewesen ist, werden sich jetzt bei allen erfahrenen Programmierern die Haare sträuben: Dim a As String Dim b As String Dim c As String a = 10 b = 20.33 c = a + b MsgBox c
"1020,33"
Listing 8.17: Unsauberes Programmieren in VB [typkonv_2.vbs]
173
8 Die Visual Basic-Sprachfamilie
Obwohl in dem Listing alle drei Variablen als Zeichenkette deklariert wurden, können Zahlen zugewiesen werden. Das Ergebnis ist dann aber nicht das, was der Programmierer sich wohl erhofft hat, denn das Pluszeichen addiert in diesem Fall nicht die Zahlen, sondern verbindet die Zeichenketten. Das Ergebnis ist also „1020,33“. Auf Grund der Tatsache, dass VBS keine Deklaration von Variablen mit einem bestimmten Datentyp kennt, würde das Beispiel dann so aussehen: Dim a Dim b Dim c a = 10 b = 20.33 c = a + b MsgBox c
"30,33"
Listing 8.18: Analog zum vorherigen Listing in VBS, aber mit anderem Ergebnis [typkonv_3.vbs]
Hier ist das Ergebnis dann 30,33. Der Subtyp der Variablen a, b und c wird ja jeweils über die letzte Wertzuweisung festgelegt. Dabei erhielten alle Variablen einen Zahlentyp als Subtyp. Um hier die Zeichenketttenverkettung zu erreichen, muss das kaufmännische Und (&) statt des Pluszeichens verwendet werden. Verwenden Sie nie das Pluszeichen zur Zeichenkettenverkettung, wenn Sie zwei Variablen miteinander verketten wollen, bei denen Sie davon ausgehen, dass Zeichenketten enthalten sind. Wenn nämlich durch Zufall beide Variablen eine Zahl enthalten, wird Visual Basic addieren und nicht verketten! Explizite Typumwandlung
Tabelle 8.11: Funktionen zur Typumwandlung
174
Explizite Typumwandlung Die folgende Tabelle zeigt Funktionen zur expliziten Typumwandlung. In VB 6.0/VBA gibt es darüber hinaus auch noch ältere Versionen der Konvertierfunktionen (Str(), Value(), ...), die Sie aber nicht mehr verwenden sollten. Im Gegensatz zu CStr() fügt die ältere Funktion Str(), die in VB 6.0/VBA verfügbar ist, immer noch ein führendes Leerzeichen hinzu. Ergebnistyp
Funktion
Boolean
CBool()
Byte
CByte()
Currency
CCur()
Date
CDate()
Single
CSng()
Double
CDbl()
Integer
CInt()
Long
CLng()
String
CStr()
Datenfelder (Arrays)
8.9
Datenfelder (Arrays)
Arrays sind Datenfelder in Form von Mengen von Variablen. Ein solches Datenfeld kann in VB bis zu 60 Dimensionen haben. Für jede Dimension kann jeweils eine Ausdehnung festgelegt werden. VB kennt zwei Formen von Arrays: 왘 Statische Arrays, bei denen Dimensionen und deren Ausdehnung fest zur Entwicklungs-
Statische
versus zeit vorgegeben werden dynamische 왘 Dynamische Arrays, bei denen die Anzahl der Dimensionen und deren Ausdehnung zur Arrays Laufzeit verändert werden können
Ein Array unterscheidet sich in VB von einer einfach skalaren Variablen durch an den Namen angehängte runde Klammern. Die runden Klammern enthalten den Index des Eintrags, auf den zugegriffen werden soll. a(5,10,8) bezeichnet zum Beispiel in einem dreidimensionalen Array das Feld mit den Koordinaten 5, 10 und 8. Die Verwendung erfolgt analog zu normalen Variablen. a(5,10,8) = wert wert = a(5,10,8)
Ein Array muss – in allen VB-Dialekten, auch VBScript – immer deklariert werden. Das heißt, Sie müssen die Variable mit Dim deklarieren. Wenn Sie auf eine nicht deklarierte Variable unter Angabe der runden Klammern zugreifen, erhalten Sie einen Fehler. Wann und wie die Dimensionierung, d.h. die Festlegung der Anzahl der Dimensionen des Datenfelds und die Ausdehnung jeder Dimension, definiert wird, ist unterschiedlich zwischen dynamischen und statischen Arrays. Deklaration
VBS
VB 6.0/VBA
Statisches Array
Dim arrayname (x,y,z,...)
Dim [x1 [y1 [z1 [As
Dynamisches Array ohne Vorgabewerte
Dim arrayname()
Dim arrayname() [As Datentyp]
Dynamisches Array mit Vorgabewerten
nicht unterstützt
nicht unterstützt
8.9.1
arrayname ( to] x2, to] y2, to] z2, ...) Datentyp]
Tabelle 8.12: Array-Deklarationen in den VB-Dialekten
Statische Arrays
Bei der Deklaration wird zumindest die Anzahl der Dimensionen und die Obergrenze für Grenzen jede Dimension angegeben. Standarduntergrenze ist 0. Dim a(x) deklariert also ein Array von 0 bis x mit x+1 Feldern.
175
8 Die Visual Basic-Sprachfamilie
In VB 6.0/VBA kann jedoch optional die Untergrenze gesetzt und ein Datentyp angegeben werden: Dim Lottozahlen(1 to 7) As Byte
In VBS ist 0 als untere Grenze jeder Dimension vorgegeben.
8.9.2 VBS/VBA/ VB 6.0
Dynamische Arrays
Bei der Deklaration in VBS/VBA/VB 6.0 werden weder die Anzahl der Dimensionen noch die Grenzen für jede Dimension angegeben. Dim arrayname() ' dynamisches Array
ReDim
Redimensionierung dynamischer Arrays Ein dynamisches Array kann mit dem Befehl ReDim zur Laufzeit dimensioniert werden, z.B. ReDim d(10,10,10). Die Ausführung von ReDim auf einem statischen Array führt zu einem Fehler.
ReDim Preserve
ReDim kann auf ein und demselben Array mehrfach ausgeführt werden. Dabei können alle Eigenschaften (Dimensionen und deren Obergrenzen und – außer in VBS – auch deren Untergrenzen) verändert werden. In der Regel geht dabei jedoch der Inhalt des Arrays verloren. Mit dem Zusatz Preserve kann der Inhalt bewahrt werden, dann ist die Redimensionierung jedoch darauf beschränkt, die Obergrenze der letzten Dimension zu verändern. Mit ReDim Preserve können weder die Anzahl der Dimensionen noch die Grenzen anderer Dimensionen verändert werden. ' Dynamisches Array deklarieren Dim domains() ' Erste Dimensionierung ReDim domains(10, 10, 10) ' Wert setzen domains(1, 1, 1) = "www.it-visions.de" ' 1. Umdimensionierung ReDim Preserve domains(10, 10, 20) ' Wert ist noch da MsgBox domains(1, 1, 1) ' 2. Umdimensionierung ReDim domains(10, 20, 20) ' Wert ist weg MsgBox domains(1, 1, 1) Listing 8.19: Redimensionierung dynamischer Arrays in VBScript [array1.vbs]
8.9.3
Array-Operationen
Dieses Kapitel behandelt die Verwendung von Arrays. Füllen eines ArrayEin Array kann auf zwei Weisen gefüllt werden: 왘 elementweise (wie schon im vorherigen Kapitel dargestellt) 왘 durch die eingebaute Funktion Array().
176
Datenfelder (Arrays)
Array() Array() erwartet als Parameter eine beliebig lange Liste von Werten und erzeugt daraus ein eindimensionales Array. Die Werte können Werte eines beliebigen elementaren Datentyps (Zahlen, Zeichenketten, Datumsangaben, Boolean) und auch Objektzeiger sein. Die Variable, die den Rückgabewert von Array() aufnimmt, muss in VBS als Variant deklariert sein. In VB 6.0 und VBA kann die Variable auch als Array gekennzeichnet sein. Das Array muss aber ein dynamisches Array vom Typ Variant sein. ' ### Arrays füllen Sub array_fuellen() Dim domains1(6) Dim domains2 Dim domain Dim x As New Collection ' --- Elementweises Füllen domains1(0) = "www.it-visions.de" domains1(1) = "www.windows-scripting.de" domains1(2) = "www.dotnetframework.de" domains1(3) = "www.Schwichtenberg.de" domains1(4) = "www.HolgerSchwichtenberg.de" domains1(5) = "www.dotnet-lexikon.de" ' --- Array ausgeben For Each domain In domains1 MsgBox domain Next ' --- Füllen per Array-Funktion domains2 = Array("www.IT-Visions.de", _ "www.windows-scripting.de", "www.dotnetframework.de", _ "www.Schwichtenberg.de", "www.HolgerSchwichtenberg.de", _ "www.dotnet-lexikon.de") ' --- Array ausgeben For Each domain In domains2 MsgBox domain Next If IsArray(Domains1) Then MsgBox "Domains1 ist ein Array!" If IsArray(domains2) Then MsgBox "Domains2 ist ein Array!" End Sub Listing 8.20: [array_ fuellen.wsf]
Typbestimmung Ob eine Variable ein Array enthält, kann mit der eingebauten Funktion isArray() geprüft isArray() werden. If IsArray(Domains1) Then MsgBox "Domains1 ist ein Array!" If IsArray(domains2) Then MsgBox "Domains2 ist ein Array!" Listing 8.21: Ausschnitt aus [array_ fuellen.wsf]
177
8 Die Visual Basic-Sprachfamilie
TypeName() TypeName() und VarType() bei Arrays Sofern die übergebene Variable ein Array ist, und hängt TypeName() an den Typnamen ein Klammernpaar „()“ an. VarType() addiert den VarType()
Wert 8192 hinzu.
Dim z(10) MsgBox TypeName(z) ' liefert Variant() MsgBox VarType(z) ' liefert 8204 z(1) = "test" MsgBox TypeName(z(1)) ' liefert String() MsgBox VarType(z(1)) ' liefert 8 Dim y() As String ' nur in VB6/VBA! MsgBox TypeName(y) ' liefert String() MsgBox VarType(y) ' liefert 8200 (8192 + 8) Listing 8.22: Datentypen bei Arrays [datentypen3.vbs]
Wertzuweisungen Kopieren
Bei einer Zuweisung eines Arrays an ein anderes Array (oder eine Variant-Variable) mit dem Zuweisungsoperator (Gleichheitszeichen) wird das Array kopiert. Anders als bei Objekten wird also hier nicht ein Verweis kopiert, sondern tatsächlich die Inhalte. Dies beweist das folgende Beispiel, in dem nach dem Zuweisen des Arrays ein Element in der Kopie geändert wird. Dadurch bleibt das ursprüngliche Array unverändert. ' === Array kopieren Sub array_kopie() Dim domains1 Dim domains2 Dim domain domains1 = Array("www.IT-Visions.de", _ "www.windows-scripting.de", "www.dotnetframework.de", _ "www.Schwichtenberg.de", "www.HolgerSchwichtenberg.de", _ "www.dotnet-lexikon.de") ' --- Kopie erzeugen domains2 = domains1 If IsArray(domains1) Then MsgBox "Domains1 ist ein Array!" If IsArray(domains2) Then MsgBox "Domains2 ist ein Array!" MsgBox "--- Inhalt von domains2:" ' --- ausgeben For Each domain In domains2 MsgBox domain Next ' --- Ändern in der Kopie domains2(1) = "www.windows-scripting.com" ' --- Vergleich der beiden Arrays MsgBox "--- Vergleich der Arrays nach Änderung an domains2():"
178
Datenfelder (Arrays)
MsgBox "domains1(1)=" & domains1(1) MsgBox "domains2(1)=" & domains2(1) ' --- Das geht nicht! 'If Domains1 = domains2 Then MsgBox "gleich" End Sub Listing 8.23: Arrays kopieren [array_kopien.wsf]
Domains1 ist ein Array! Domains2 ist ein Array! --- Inhalt von domains2: www.IT-Visions.de www.windows-scripting.de www.dotnetframework.de www.Schwichtenberg.de www.HolgerSchwichtenberg.de www.dotnet-lexikon.de --- Vergleich der Arrays nach Änderung an domains2(): domains1(1)=www.windows-scripting.de domains2(1)=www.windows-scripting.com Listing 8.24: Ausgabe des obigen Script
Arrays vergleichen Arrays können nicht mit dem Gleichheitszeichen verglichen werden. Sie können selbst eine Routine schreiben, die die Inhalte elementweise vergleicht. ' --- Das geht nicht! 'If Domains1 = domains2 Then MsgBox "gleich"
Arrays als Funktionsrückgabewerte Eine Funktion kann ein Array als Rückgabewert liefern. Dabei ist unter VBS zu beachten, dass die Variable, die den Rückgabewert aufnehmen soll, nicht als Array, sondern als einfacher Varianttyp definiert werden muss. Dim domain Dim domains domains = get_Domains For Each domain In domains MsgBox domain Next
Beispiel VBS
In VBS ist hier kein Klammernpaar erlaubt!
Function get_Domains() Dim domains(5) domains(0) = "www.it-visions.de" domains(1) = "www.windows-scripting.de" domains(2) = "www.dotnetframework.de" domains(3) = "www.Schwichtenberg.de" domains(4) = "www.HolgerSchwichtenberg.de"
179
8 Die Visual Basic-Sprachfamilie
domains(5) = "www.dotnet-lexikon.de" get_Domains = domains End Function Listing 8.25: [_array_als_Funktionsrueckgabewert.vbs] Beispiel VB 6.0 untypisiert
Beispiel 2 In VB 6.0 und VBA kann die Variable auch als Array gekennzeichnet sein. Das Array muss aber ein dynamisches Array vom Typ Variant sein. ' === Arrays als Rückgabewerte von Funktionen (untypisiert) Sub array_funktionen1() Dim domain Dim domains() domains = get_Domains1 For Each domain In domains MsgBox domain Next End Sub ' ### Diese Funktion liefert ein Array als Rückgabewert Function get_Domains1() ReDim domains(5) domains(0) = "www.it-visions.de" domains(1) = "www.windows-scripting.de" domains(2) = "www.dotnetframework.de" domains(3) = "www.Schwichtenberg.de" domains(4) = "www.HolgerSchwichtenberg.de" domains(5) = "www.dotnet-lexikon.de" get_Domains1 = domains End Function
Beispiel VB 6.0 typisiert
Beispiel 3 Natürlich kann das Array in VB 6.0 und VBA auch typisiert werden. In dem folgenden Beispiel enthält das Array Elemente des Typs String. ' === Arrays als Rückgabewerte von Funktionen (typisiert) Sub array_funktionen2() Dim domain As Variant Dim domains() As String domains = get_Domains2 For Each domain In domains MsgBox domain Next End Sub ' ### Diese Funktion liefert ein Array als Rückgabewert Function get_Domains2() As String() ReDim domains(5) As String domains(0) = "www.it-visions.de" domains(1) = "www.windows-scripting.de" domains(2) = "www.dotnetframework.de" domains(3) = "www.Schwichtenberg.de" domains(4) = "www.HolgerSchwichtenberg.de"
180
Bedingungen
domains(5) = "www.dotnet-lexikon.de" get_Domains2 = domains End Function
8.10 Bedingungen VB kennt zwei typische Sprachkonstrukte zur bedingten Ausführung von Programmteilen Fallunterscheidungen auf der Grundlage von Fallunterscheidungen: 왘 If...Then 왘 Case...Select
8.10.1
If...Then
Die Grundstruktur von If...Then ist:
If...Then
If Bedingung Then Anweisung
Wenn anstelle einer einzelnen Anweisung ein ganzer Anweisungsblock bedingt ausgeführt werden soll, 왘 darf direkt nach Then kein Befehl stehen; 왘 muss das Ende des Anweisungsblocks mit End If gekennzeichnet werden.
If Bedingung Then Anweisung1 Anweisung2 ... End If
Als Bedingung ist jeder Ausdruck erlaubt, der True oder False ergibt. If Geschlecht = "w" Then MsgBox "Sie sind eine Frau!"
Bei Boolean-Werten, die sowieso True oder False enthalten, ist die Ausformulierung der Bedingung mit = True oder = False optional. Beide nachfolgenden Statements sind erlaubt. If DebugMode = True Then MsgBox "Schritt 2 ausgeführt". If DebugMode Then MsgBox "Schritt 2 ausgeführt".
Die typische Struktur If...Then kann mit den Schlüsselwörtern Else und ElseIf so erwei- Else, ElseIf tert werden, dass insgesamt mehrere Fälle in einer Struktur abgeprüft werden können. Sie können auch mehrere If...Then-Strukturen ineinander verschachteln. If Bedingung Then Anweisungsblock [ElseIf Bedingung2 Then Anweisungsblock] [Else Anweisungsblock] End If
181
8 Die Visual Basic-Sprachfamilie
Geschlecht = "n" ... If Geschlecht = "w" Then Artikel = "die" ElseIf Geschlecht = "m" Then Artikel = "der" ElseIf Geschlecht = "n" Then Artikel = "das" Else MsgBox "Fehler!" End If Listing 8.26: Beispiel zu If...Then...Else [if_beispiel2.vbs]
8.10.2 Select...Case
Select...Case
Mit Select...Case können auf übersichtliche Art und Weise mehrere Fälle behandelt werden. Der Vorteil von Select...Case gegenüber verschachtelten If...Then-Ausdrücken ist die größere Übersichtlichkeit. Das Grundgerüst lautet: Select Case Ausdruck Case Wert1: Anweisungsblock Case Wert2, Wert 3: Anweisungsblock ... Case Bedingung n [Case Else: Anweisungsblock] End Select
Case-Blöcke
Dabei ist Ausdruck üblicherweise eine Variable oder Konstante, die mit den folgenden CaseAnweisungen auf verschiedene Werte abgeprüft wird. Sofern eine Case-Anweisung zutrifft, wird der nach dem Doppelpunkt stehende Anweisungsblock ausgeführt. Wenn mehrere Bedingungen zutreffen, wird nur der erste zutreffende Case-Block ausgeführt. Wenn keine Bedingung zutrifft, wird der optionale Case-Else-Block ausgeführt. Wenn dieser nicht angegeben ist, wird keine Anweisung ausgeführt. Dim x x = 10 '... Select Case x Case 0: text = "keine Person" Case 1: text = "eine Person" Case 2: text = "zwei Personen" Case 3, 4, 5: text = "eine kleine Gruppe" Case Else: text = "zu viele Leute!" End Select MsgBox text Listing 8.27: Beispiel zu Select...Case [selcase.vbs]
Unter- Ein Case-Statement kann mehrere Werte enthalten. In Visual Basic Script kann das Caseschiede zu Statement nur auf Gleichheit überprüfen. Operatoren wie < und > sind nicht erlaubt. VB VB 6.0/VBA
182
Bedingungen
6.0/VBA gestatten auch andere Operatoren. Dies muss jedoch mit dem Schlüsselwort Is angezeigt werden. Case Is "Alter = 969" u.info ' Methodenaufruf -> "Methusalem ist 969 Jahre alt!" u.Kennwort = "123" ' Property Set ' -> Kennwort zu kurz! 'MsgBox u.Kennwort ' Property Get -> Nicht erlaubt! Listing 8.55: Anwendungsbeispiel für Property-Routinen [_User-Klasse.vbs]
206
Objektbasierte Programmierung
Das Problem mit den Standardeigenschaften Property-Routinen bieten auch die StandardMöglichkeit, ein Standardattribut (Default Property) festzulegen, das immer dann verwen- attribut det wird, wenn auf eine Objektvariable ohne Angabe eines Mitgliedsnamens zugegriffen und zugleich ein elementarer Datentyp erwartet wird. Dies ist jedoch sehr schlechter Stil, denn eine Objektvariable bezeichnet normalerweise das ganze Objekt und nicht nur ein Attribut. Als Zeiger auf das ganze Objekt wird eine Objektvariable bei der Zuweisung an eine andere Objektvariable und bei der Übergabe als Parameter an eine Unterroutine verstanden. Gegeben sei eine Klasse clsProblem mit dem Standardattribut Name und dem zusätzlichen Beispiel Attribut Bemerkung. Folgendes Code-Beispiel macht die Verwirrung deutlich: Sub attributausgabe(obj) MsgBox obj MsgBox obj.Bemerkung End Sub Sub teste_problem() Dim p As New clsProblem p.Name = "Default Property-Problem" p.Bemerkung = "Bug oder Feature?" MsgBox p ' Standardattribut x = p ' Standardattribut Set y = p ' Zeiger! attributausgabe p ' Zeiger ! Call attributausgabe(p) ' Zeiger! attributausgabe (p) ' Standardattribut End Sub ' ### Unterroutine zum Default Property-Problem Sub attributausgabe(obj) MsgBox obj MsgBox obj.Bemerkung End Sub Listing 8.56: Veranschaulichung des Default Property-Problems [_Problem-Klasse.vbs]
MsgBox p und die Zuweisung x = p sind Zugriffe auf das Standardattribut, die Zuweisung Erläuterung mit Set und die beiden ersten Prozeduraufrufe verwenden den Objektzeiger. Die Prozedur attributausgabe() erhält dabei einen Zeiger auf den Zeiger. MsgBox obj greift also wieder auf das Standardattribut zu.
Beim letzten Aufruf tritt allerdings wieder ein Problem zu Tage, das es in ähnlicher Form auch bei elementaren Datentypen gibt (vgl. Kapitel 8.12): Wenn eine Unterroutine nur einen Parameter hat, dieser Parameter in runden Klammern steht und das Unterprogramm keinen Rückgabewert liefert oder das Hauptprogramm den gelieferten Rückgabewert nicht empfängt, dann wird nicht der Zeiger übergeben, sondern das Standardattribut! Das ist für den ersten Befehl MsgBox obj in der Prozedur attributausgabe() noch kein Problem, aber beim Zugriff auf obj.Bemerkung kommt es zum Programmabbruch, denn die übergebene Zeichenkette hat keine Attribute. Das kann in einer anderen Konstellation noch unangenehmer werden: Wenn das Standardattribut selbst wieder ein Zeiger auf ein Objekt ist, dann erhält die Unterroutine zwar einen Zeiger, aber den falschen!
207
8 Die Visual Basic-Sprachfamilie
Achten Sie genau auf die Regeln für die Klammersetzung bei Prozeduren und Funktionen. Sie können das Problem auch vermeiden, indem Sie sich die Mühe machen, Standardattribute immer explizit anzugeben.
8.14.8 Garbage Collection
Objektvernichtung
Alle Visual Basic-Dialekte verfügen über eine automatische Entsorgung des von Variablen belegten Speicherplatzes (Garbage Collection). Die Vernichtung einer Objektinstanz erfolgt, wenn es keinen Zeiger auf eine Objektinstanz mehr gibt. Nicht mehr benötigte Speicherbereiche werden so automatisch freigegeben, wenn der Geltungsbereich (Scope) einer Objektvariablen verlassen wird. Auch wenn oft das Gegenteil behauptet wird: Die explizite Vernichtung mit der Anweisung Set obj = Nothing ist optional (siehe dazu [WES99b]).
Set obj = Nothing
Sie können das Konstrukt Set obj = Nothing jedoch dazu nutzen, ein Objekt vor dem Verlassen des Geltungsbereichs wieder freizugeben. Wenn mehrere Objektvariablen auf die betreffende Instanz verweisen, müssen all diese Objektvariablen auf „Nothing“ gesetzt werden. Erst dann gibt Visual Basic die Instanz frei. ' Deklaration Dim o1 Dim o2 Dim o3 ' Zwei Instanzen erzeugen Set o1 = New Mathe ' Wertzuweisungen Set o2 = o1 Set o3 = o2 ' Zeiger zurücksetzen... Set o1 = Nothing Set o2 = Nothing ' Objekt lebt noch! o3.About ' Endgültige Objektvernichtung Set o3 = Nothing Listing 8.57: Beispiel zur Lebensdauer von Objekten [oo_vernichtung.vbs]
8.14.9 Objektmengen
208
Objektmengen (Collections)
Alle Visual Basic-Dialekte können in COM-Komponenten definierte Objektmengen nutzen. VB 6.0/VBA können darüber hinaus eigene Objektmengen erzeugen. Die Objektmengen können heterogen sein, d.h., sie können Instanzen verschiedener Klassen enthalten. Ebenso kann ein und dieselbe Instanz mehrfach enthalten sein. In VBS können Sie zur Verwendung von Objektmengen die COM-Klasse Scripting.Dictionary verwenden (siehe Kapitel 10.2).
Objektbasierte Programmierung
Praktische Beispiele zur Arbeit mit Objektmengen finden Sie in der Beschreibung der einzelnen COM-Komponenten später in diesem Buch. Lesezugriff auf Objektmengen Der Zugriff auf Objektmengen ist in allen VB-Dialekten gleich. Es gibt zwei Möglichkeiten des Zugriffs auf die enthaltenen Objekte: 왘 Zugriff über ein Schlüsselfeld 왘 Zugriff über Iteration über alle Elemente
Voraussetzung für den Zugriff über ein Schlüsselfeld ist, dass ein solches überhaupt existiert. Item() VB-Objektmengen besitzen ebenso wie die meisten COM-Objektmengen die Methode Item() (leider wird Item() oft auch als Attribut implementiert, die Syntax bleibt jedoch gleich; siehe die Erläuterungen in Kapitel 7). Set obj = col.Item("key")
Diese Schreibweise lässt sich in der Regel verkürzen auf col("key"), da Item das Standardattribut ist. In VB 6.0/VBA ist eine weitere Verkürzung auf col!key möglich. Damit ist der Schlüsselname dann aber zur Entwicklungszeit vorgegeben. Bei der Schreibweise mit Klammern kann natürlich auch ein Variablenname angegeben werden. key = "ID" set obj = col.Item(key)
Als Schlüsselwert kann in der Regel auch ein Wert angegeben werden, um die enthaltenen Objekte gemäß ihrer Reihenfolge anzusprechen. set obj = col.Item(1)' Das erste Element set obj = col.Item(7)' Das siebte Element
VB-Objektmengen beginnen bei 1 zu zählen. Viele Objektmengen in COM-Objektmodellen starten dagegen bei 0! Count() liefert die Anzahl der in einer Objektmenge enthaltenen Elemente.
Count()
Iteration über die Elemente einer Objektmenge Wenn die Schlüssel nicht bekannt sind und ein Element gesucht werden soll oder alle Elemente der Objektmenge aufgelistet werden sollen, dann ist eine Iteration über alle Elemente notwendig. Visual Basic bietet mit For...Each eine sehr elegante Sprachkonstruktion an, um die Iteration über eine Objektmenge durchzuführen. Diese Möglichkeit funktioniert oft auch dann, wenn die Objektmenge keine oder unzuverlässige Informationen über die Anzahl der enthaltenen Objekte anbietet. For each obj in col obj.DoSomething Next
For...Each
209
8 Die Visual Basic-Sprachfamilie
For...Next
Eine alternative Möglichkeit ist die Iteration mit For...Next, sofern die Objektmenge ein Count()-Attribut besitzt und numerische Indizes unterstützt. For i = 0 To col.Count-1 col.item(i).DoSomething Next
Add()
Veränderung einer Objektmenge Das Anfügen neuer Elemente erfolgt über die Methode Add(): col.Add obj,[key],[Before],[After]
Erster Parameter ist ein Zeiger auf das Objekt, das der Objektmenge hinzugefügt werden soll. Optional ist die Angabe eines Schlüssels in Form einer Zeichenkette. Einige VBObjektmengen und einige COM-Objektmengen bieten darüber hinaus auch die Möglichkeit, mit zwei weiteren Schlüsseln anzugeben, an welcher Stelle der Liste das Objekt eingefügt werden soll. Remove()
Zum Entfernen aus der Liste ist der Schlüssel notwendig. col.Remove key
Erzeugung von Objektmengen in VB 6.0/VBA VB 6.0/VBA bringen eine vordefinierte Klasse Collection mit, von der Sie Instanzen erzeugen können. Im nachstehenden Beispiel wird eine Objektmenge mit zehn Instanzen der Klasse Mathe gefüllt. Anschließend gibt es zwei Iterationen über die Objektmenge. In der ersten Runde wird das Attribut x ausgelesen, in der zweiten Runde wird die Methode Add() bei allen ausgeführt. Sub oo_newcollection() Dim m As Mathe Dim col As New Collection ' -- Aufbau der Collection For a = 1 To 10 Set m = New Mathe m.x = a m.y = a + 100 col.Add m, CStr(a) Next ' -- Iteration über Collection For i = 1 To col.Count say col(i).x Next For Each obj In col say obj.Add Next End Sub Listing 8.58: Beispiel zur Erzeugung und Verwendung einer Collection [CD: /code/sprachen/_alle/ vb-beispiele.vbp]
210
Objektbasierte Programmierung
8.14.10 Ereignisse Die Fähigkeit, als Event Publisher oder Event Subscriber zu agieren, ist in den verschiedenen Visual Basic-Dialekten unterschiedlich stark ausgeprägt: 왘 Sowohl VB 6.0 und VBA als auch VBS ermöglichen es Klassen, auf die Ereignisse
Class_Initialize() und Class_Terminate() zu reagieren. 왘 VB 6.0/VBA-Klassen können Event Publisher sein, die eigene Ereignisse definieren und
an ihre Umwelt aussenden. VBS-Klassen können keine Event Publisher sein.
KlassenEreignisse Event Publisher
왘 VB 6.0/VBA-Klassen können Event Subscriber für VB- und COM-Klassen sein. VB 6.0-
Event
Klassenereignisse Oft ist es sinnvoll, dass bei der Erzeugung einer neuen Objektinstanz oder bei deren Vernichtung Vorgänge ausgeführt werden, z.B. die Initialisierung von Variablen bei der Objekterzeugung oder die Freigabe von Ressourcen bei der Objektvernichtung. Sicherlich ist es möglich, dafür jeweils eine Methode anzubieten. Jedoch ist das Objekt dann auf die Disziplin seines Nutzers angewiesen.
Class_Initialize() und Class_ Terminate()
Module können keine Event Subscriber sein. In VBS ist der Empfang von Ereignissen Subscriber eine Funktion, die vom Scripting Host bereitgestellt wird. Das Abonnement auf ein Ereignis wird in jedem Scripting Host anders definiert (siehe Kapitel 9).
Dies kann mit den Ereignissen Class_Initialize() und Class_Terminate() besser gelöst werden. Diese beiden Ereignisse stellen einen Sonderfall dar, bei dem das Schlüsselwort Class für die Selbstreferenz auf die eigene Klasse steht. Ereigniserzeuger ist in diesem Fall die VB-Laufzeitumgebung. Class_Intialize() entspricht einem Konstruktor (ohne Parameter) und Class_Terminate() einem Desktruktor (vgl. Erläuterungen in Anhang A). Private Sub Class_Initialize End Sub Private Sub Class_Terminate End Sub
Das nachfolgende Listing zeigt ein Beispiel: Nacheinander sollen die drei Dialogfenster „Hallo, ich bin jetzt hier!“, „Ich tue etwas...“ und „Und Tschüss!“ erscheinen. Class clsHierUndWeg ' -- Ereignisbehandlung Private Sub Class_Initialize() MsgBox "Hallo, ich bin jetzt hier!" End Sub Private Sub Class_Terminate() MsgBox "Und Tschüss!" End Sub ' -- Methode Sub dosomething() MsgBox "Ich tue etwas..." End Sub End Class ' --- Hauptprogramm Dim o
211
8 Die Visual Basic-Sprachfamilie
set o = new clsHierUndWeg e.dosomething Set o = Nothing Listing 8.59: Beispiel für Klassenereignisse in VBS [_hierundweg.vbs] Konstruktoren und Destruktoren
Das Class_Initialize-Ereignis ist nur ein Teil dessen, was in anderen objektorientierten Programmiersprachen als Konstruktor bezeichnet wird. Üblicherweise ist man in der Lage, bei der Objekterzeugung auch Parameter anzugeben, die dann einer bestimmten Routine, Konstruktor genannt, übergeben werden. Erst Visual Basic .NET unterstützt die Möglichkeit, bei der Instanziierung Parameter anzugeben, die Class_Initialize empfangen können. Eigene Ereignisse in VB 6.0/VBA Die Ereignisunterstützung in Scripts wird im Zusammenhang mit den jeweiligen Scripting Hosts beschrieben werden. Die Ausführungen in diesem Abschnitt beziehen sich ausschließlich auf VB 6.0/VBA. Das grundsätzliche Vorgehen ist in VBS jedoch ähnlich.
Publisher
Eine Klasse wird Event Publisher, indem sie ein Ereignis mit dem Schlüsselwort Event definiert und dieses Ereignis irgendwann mit RaiseEvent() auslöst. Event jetztistwaslos() ' ... Sub dosomething() ' ... RaiseEvent jetztistwaslos ' ... End Sub Listing 8.60: Definition und Aussenden eines Ereignisses im großen VB und in VBA (nicht in VBS!)
Subscriber
Eine VB-Routine, die die Ereignisse von einem Event Publisher abonnieren will, gibt bei der Deklaration der Objektvariablen für diese Klasse an, dass sie sich für deren Ereignisse grundsätzlich interessiert. Sie wird dadurch Subscriber dieses Event Publisher. Der Subscriber definiert danach Ereignisbehandlungsroutinen für die Ereignisse, die ihn interessieren und die er behandeln möchte. Er ist nicht verpflichtet, alle Ereignisse des Publishers zu behandeln. Ereignisbehandlungsroutinen werden nicht wie Attribute und Methoden durch einen Punkt, sondern durch einen Unterstrich ( „_“ ) von dem Namen der Objektvariablen getrennt. Dim WithEvents o As clsEventServer Private Sub o_jetztistwaslos() MsgBox "Da war was los!" End Sub Listing 8.61: Abo eines Ereignisses in VB 6.0/VBA (nicht in VBS!)
212
Objektbasierte Programmierung
8.14.11 Vererbung und Mehrfachschnittstellen Einer der Hauptkritikpunkte an der Umsetzung objektorientierter Prinzipien in Visual SchnittBasic war die fehlende Vererbung. VBS unterstützt keine Formen der Vererbung. Dieses stellenvererbung Kapitel bezieht sich also nur auf VB 6.0/VBA. versus Implemen-
VB 6.0 und VBA 6.0 unterstützen nur Schnittstellenvererbung, d.h., eine Unterklasse wird tierungsgezwungen, alle Mitglieder einer Oberklasse ebenfalls zu implementieren. Damit kann vererbung erreicht werden, dass die beiden Klassen polymorph zueinander sind; es ist jedoch kein Instrument zur Wiederverwendung. In VB ab Version 5.0 und VBA ab Version 5.0 können Mehrfachschnittstellen für Klassen implementiert werden. Da die Unterstützung von Mehrfachschnittstellen nachträglich in VB aufgenommen wurde, werden Schnittstellen auf kleinen Umwegen über die Definition von abstrakten Basisklassen erstellt. Visual Basic Script unterstützt weder die Definition noch die Nutzung von Mehrfachschnittstellen, da ein Schnittstellenwechsel in VBS nicht möglich ist. Dies ist aus sprachinterner Sicht kein Problem, denn wo keine Mehrfachschnittstellen definiert werden können, müssen sie auch nicht benutzt werden.
Zunächst muss man für jede gewünschte Schnittstelle eine abstrakte Klasse definieren, also Implements eine Klasse mit Attributdefinition und Methodenrümpfen, aber ohne Implementierung. Erst dann wird die eigentliche Klasse definiert, wobei mit Hilfe von Implements Bezug auf die zuvor fertig gestellten abstrakten Basisklassen genommen wird. Implements erzwingt, dass alle in den abstrakten Basisklassen definierten Attribute und Methoden hier implementiert werden müssen. Dabei ist syntaktisch Folgendes zu beachten: 왘 Die Attribute müssen mit Property-Routinen implementiert werden. Einfache Attri-
butdefinitionen funktionieren hier leider nicht. 왘 Der Name der abstrakten Basisklasse, deren Attribut oder Methode implementiert wer-
den soll, muss durch einen Unterstrich getrennt vorangestellt werden (leider gibt es damit neben der Verwendung in Ereignisbehandlungsroutinen eine zweite Bedeutung dieser Notation). 왘 Alle implementierten Attribute und Methoden müssen als privat (Private) deklariert sein. Wenn Sie sich darüber wundern, sind Sie nicht allein, denn diese Mitglieder sollen ja dem Objektnutzer zur Verfügung stehen. In diesem Fall sind die Mitglieder aber dann trotz der Private-Deklaration öffentlich. Ohne Auszeichnung als Private wären die implementierten Member zusätzlich Teil der Standardschnittstelle der Klasse – allerdings mit ihrem unnatürlichen Namen gemäß oben genannter Namenskonvention. Hier zeigt sich deutlich, dass man versucht hat, mit der bisher bekannten Menge an Schlüsselwörtern neue Funktionen zu realisieren, für die man besser ein neues Schlüsselwort eingeführt hätte.
213
8 Die Visual Basic-Sprachfamilie
Definition von Mehrfachschnittstellen Das folgende Beispiel handelt von einem Multifunktionsgerät, das sowohl als Drucker als auch als Fax und Scanner verwendet werden kann. Das komplette Beispiel finden Sie auf der CD als VB-Projektdatei [CD:/code/ sprachen/vb_mehrfachschnittstellen/geraete.vbp]. Dort sind drei abstrakte Basisklassen IFax, IScanner und IPrinter definiert. Bild 8.6: Die Abbildung zeigt die Definition der drei Schnittstellen IFax, IPrinter und IScanner.
IFax
IPrinter
Klasse Geraete.AllinOne
Bild 8.7: MehrfachschnittstellenBeispiel Multifunktionsgerät
214
IScanner
Objektbasierte Programmierung
Definition einer Klasse mit mehreren Schnittstellen Das folgende Listing zeigt die Klasse AllInOne: ' --- Festlegung der zu implementierenden Schnittstellen Implements IFax Implements IScanner Implements IPrinter ' --- Private Variablen Dim FaxStatus As Integer Dim ScanStatus As Integer ' --- Implementierung der Scanner-Schnittstelle Private Sub IScanner_ScanPage() MsgBox "Seite wird gescannt..." ScanStatus = 1 End Sub Private Property Get IScanner_ScanStatus() As Integer IScanner_ScanStatus = ScanStatus End Property Private Property Let IScanner_ScanStatus(ByVal vNewValue As Integer) ScanStatus = vNewValue End Property ' --- Implementierung der Fax-Schnittstelle Private Sub IFax_SendFax() MsgBox "Telefax wird gesendet..." FaxStatus = 1 End Sub Private Property Get IFax_FaxStatus() As Integer IFax_FaxStatus = FaxStatus End Property Private Property Let IFax_FaxStatus(ByVal vNewValue As Integer) FaxStatus = vNewValue End Property ' --- Implementierung der Drucker-Schnittstelle Private Sub IPrinter_PrintOut() MsgBox "Dokument wird gedruckt!" End Sub Listing 8.62: Implementierung einer Klasse mit Mehrfachschnittstellen (nicht möglich in VBS!)
Nutzung von Objekten mit mehreren Schnittstellen Außerdem soll hier noch gezeigt werden, wie Mehrfachschnittstellen benutzt werden. Wenn ein Objekt über mehrere Schnittstellen verfügt, dann hat VB immer die Schnittstelle im Zugriff, die dem Typ der Objektvariablen entspricht. Ein Wechsel der Schnittstelle erfolgt also mit:
Nutzung von Mehrfachschnittstellen
Dim x as neueSchnittstelle set x = y
Hierbei ist y ein Zeiger auf die alte Schnittstelle und x muss als eine Objektvariable vom Typ der neuen Schnittstelle deklariert worden sein.
215
8 Die Visual Basic-Sprachfamilie
Sub main() Dim F As IFax Dim S As IScanner Dim P As IPrinter Dim A As App ' Objekt instanziieren Set F = New AllInOne ' Aufruf aus Interface IFax F.SendFax MsgBox F.FaxStatus ' Schnittstelle wechseln Set P = F P.PrintOut ' Schnittstelle wechseln Set S = F S.ScanPage MsgBox S.ScanStatus ' Fehler: Methode nicht gefunden S.SendFax ' Fehler: Typen unverträglich Set A = F End Sub Listing 8.63: Verwendung der im vorherigen Listing definierten Mehrfachschnittstellen (nicht möglich in VBS!)
Der vorletzte Befehl führt zu einem Fehler, weil die Methode SendFax() über die Schnittstelle IScanner, auf die S zeigt, nicht im Zugriff ist. Der letzte Befehl führt zu einem Fehler, weil die Klasse AllInOne nicht über eine Schnittstelle App verfügt.
8.15 Nutzung von COM und DCOM Nutzung
Alle Visual Basic-Dialekte verfügen über die Möglichkeit, auf dem System vorhandene COM-Komponenten zu nutzen. Allerdings gibt es einen entscheidenden Unterschied: VBS kann – wie andere Scriptsprachen auch – nur auf automationsfähige Komponenten via IDispatch-Schnittstelle zugreifen.
Erstellung
Die Erzeugung neuer COM-Komponenten wird in den verschiedenen Visual Basic-Dialekten allerdings unterschiedlich unterstützt: 왘 Das große VB kann seit Version 4.0 die wichtigsten Typen von COM-Komponenten in
Form von COM-DLLs und COM-EXEs erstellen. 왘 VBA kann seit der Version 5.0 einige wenige ausgewählte Arten von COM-Komponenten erstellen. 왘 Mit VBS können COM-Komponenten nur in Form von Scriptlets erstellt werden.
216
Nutzung von COM und DCOM
New-Operator
VB
VBA
VBS
Ja
Ja
nur für VBS-Klassen
CreateObject() (lokal)
Ja
Ja
Ja
CreateObject() (entfernt)
Ja, ab v6.0
Ja, ab v6.0
Ja, ab v5.0
GetObject()
Ja
Ja
Ja
8.15.1
Tabelle 8.16: Aktivierungsmöglichkeiten von COMObjekten in VB-Dialekten im Vergleich
Instanziierung von COM-Komponenten
Für den Zugriff auf bestehende COM-Komponenten gibt es in Visual Basic zwei grundsätzliche Möglichkeiten: 왘 Erzeugung einer neuen Instanz einer COM-Klasse mit dem New-Operator oder der
CreateObject()-Funktion 왘 Zugriff auf eine bestehende Instanz aus der Running Objects Table (ROT) oder auf eine
persistente Instanz mit der GetObject()-Funktion Der Unterschied zwischen New und CreateObject() ist folgender: 왘 In VBS kann zur Instanziierung von COM-Klassen nur CreateObject() verwendet wer-
New versus CreateObject()
den. Mit New können in VBS nur VBS-Klassen oder COM-Klassen instanziiert werden. Ausnahmen bilden COM-Klassen, die in der gleichen Komponente wie die Scripting Engine selbst interpretiert sind. Eine solche Klasse ist RegExp. 왘 Mit CreateObject() können nur COM-Klassen, aber keine VB-Klassen instanziiert werden. 왘 Bei New sind der Komponenten- und der Klassenname im Programmcode statisch festgelegt. CreateObject() erwartet eine Zeichenkette, für die auch eine zuvor zur Laufzeit belegte Variable verwendet werden kann. Komponente = "Word" Klasse = "Application" ProgID = Komponente & "." & Klasse Set o = CreateObject(ProgID) 왘 CreateObject() erlaubt auch die Angabe einer CLSID. 왘 CreateObject() sucht die angegebene ProgID bzw. CLSID direkt in der Registrierungs-
datenbank unter HKEY_CLASSES_ROOT. New verlangt, dass die angegebene ProgID in einer in das VB 6.0/VBA-Projekt eingebundenen Typbibliothek definiert ist. Sofern die Typbibliothek nicht den Registrierungsdatenbankeinträgen entspricht (vgl. Ausführungen zum Zeitplandienst im COM-Komponentenhandbuch), weicht die bei New zu verwendende ProgID von der ProgID bei CreateObject() ab. Sofern der Klassenname innerhalb der eingebundenen Typbibliothek eindeutig ist, ist die Angabe des Komponentennamens bei New nicht notwendig. 왘 Bei der Verwendung innerhalb eines Objekts, dessen Klasse im Microsoft Transaction Server 2.0 (siehe Kapitel 7) installiert ist, erzeugt CreateObject() eine Instanz in einem neuen Objektkontext und New eine Instanz ohne Objektkontext.
217
8 Die Visual Basic-Sprachfamilie
왘 Für COM-Klassen, die in mehreren Versionen installiert sind, kann mit CreateObject()
explizit definiert werden, welche Version instanziiert werden soll. New verwendet immer die aktuelle Version. 왘 Mit CreateObject() können auch Instanzen auf entfernten Rechnern erzeugt werden. Create- Instanziieren mit CreateObject() CreateObject() kann nur in Zusammenhang mit Object() der Set-Anweisung benutzt werden.
set o = CreateObject (komponente.klasse.version [,computername])
Beispiele: Set Set Set Set
o o o o
= = = =
CreateObject("Scripting.FileSystemObject") CreateObject("MAPI.Session") CreateObject("Word.Application") CreateObject("Word.Application.12")
Listing 8.64: Beispiele für die lokale Instanziierung Fernaktivie- Fernaktivierung Ab VB 6/7, VBA 6.0 und VBS 5.0 unterstützt Visual Basic den zusätzlirung chen Parameter Computername. Somit ist es möglich, auf einfache Weise DCOM-Aufrufe zu
realisieren. set o = CreateObject("Word.Application","\\sonne2000") set o = CreateObject("Scripting.FileSystemObject ","\\sonne2000") Listing 8.65: Beispiele für die entfernte Instanziierung New
Instanziieren mit dem New-Operator in VB 6.0/VBA Der New-Operator kann zur Erzeugung neuer Instanzen von COM-Klassen nur in VB 6.0/VBA benutzt werden. New benötigt immer Informationen aus der Typbibliothek der Komponente. Diese muss also zuvor eingebunden werden. Dabei kann New entweder bei der Deklaration einer Variablen Dim o as new Komponente.Klasse
oder mit einer Objektzuweisung mit Set verwendet werden. Dim o As Komponente.Klasse Set obj = new Komponente.Klasse
Die erste Variante ist marginal langsamer als die zweite, da Visual Basic intern bei jedem Objektzugriff eine zusätzliche Überprüfung der Objektvariablen durchführt. Tabelle 8.17: Beispiele zur Anwendung des NewOperators
218
Verwendung in Deklaration
Dim obj As new Word.Application
Verwendung mit Set
Dim obj As Word.Application Set obj = new Word.Application
Nutzung von COM und DCOM
Frühes und spätes Binden Fälschlicherweise wird oft behauptet, der Unterschied Bindungszwischen dem New-Operator und der CreateObject()-Funktion sei der Bindungszeitpunkt. zeitpunkt Der Bindungszeitpunkt wird in Visual Basic lediglich durch die Deklaration angegeben. 왘 Wird in der Deklaration der Variablen der Typ genannt, erfolgt frühe Bindung mit Query-
Interface() und vTables. 왘 Nur wenn die Variable nicht typisiert (also vom Typ Variant) oder As Object deklariert
ist, erfolgt späte Bindung mit IDispatch. Visual Basic Script, das keine Typendeklaration kennt, verwendet folglich immer spätes Binden! Die Typisierung einer Objektvariablen auf eine COM-Klasse erfordert immer die Einbindung der Typbibliothek der Komponente. Ohne eine Typbibliothek sind VB 6.0/VBA nicht besser dran als VBS und können nur spät mit IDispatch binden. Dim obj As new TestKomponente.TestKlasse Set obj = CreateObject("TestKomponente.TestKlasse") Listing 8.66: Frühe Bindung mit CreateObject()
Dim obj As new TestKomponente.TestKlasse Set obj = new TestKomponente.TestKlasse Listing 8.67: Frühe Bindung mit New
Dim obj Set obj = CreateObject("TestKomponente.TestKlasse") Listing 8.68: Späte Bindung mit CreateObject()
Dim obj As Object Set obj = new TestKomponente.TestKlasse Listing 8.69: Späte Bindung mit New
TypeName() Die VB-Funktion TypeName() funktioniert auch bei COM-Klassen und liefert den Klassennamen der COM-Klasse.
8.15.2
Zugriff auf bestehende Instanzen
Während CreateObject() eine neue Instanz einer Klasse erzeugt, ist mit GetObject() der GetObject() Zugriff auf bereits bestehende Instanzen einer Klasse aus der Running Objects Table (ROT) oder einer persistenten Instanz (z.B. aus dem Dateisystem) möglich. GetObject() hat zwei Parameter, von denen mindestens einer angegeben sein muss: entweder ein Moniker für die gewünschte Instanz oder eine ProgID für die gewünschte Klasse. set o = GetObject([moniker] [,class])
219
8 Die Visual Basic-Sprachfamilie
Moniker
Wird nur ein Moniker angegeben, sucht GetObject() die entsprechende Instanz und gibt bei Erfolg einen Zeiger darauf zurück. Sofern bei GetObject() der optionale Parameter ProgID nicht angegeben ist, wird die Datei immer mit der Anwendung geöffnet, mit der die Dateierweiterung verknüpft ist. Die Verknüpfung ist in der Registrierungsdatenbank (in HKEY_CLASSES_ROOT) hinterlegt.
Class
Wird nur eine class angegeben, sucht GetObject() irgendeine Instanz dieser Klasse in der Running Objects Table. Wird eine Instanz gefunden, wird der Zeiger darauf zurückgeliefert. Wird keine Instanz gefunden, verhält sich GetObject() wie CreateObject() und erzeugt eine neue Instanz. Achtung: Diese Funktion funktioniert nicht in älteren VBScript-Implementierungen.
Dateierweiterung
Sofern bei GetObject() der optionale Parameter class nicht angegeben ist, wird die Datei immer mit der Anwendung geöffnet, mit der die Dateierweiterung verknüpft ist. Die Verknüpfung ist in der Registrierungsdatenbank (in HKEY_CLASSES_ROOT) hinterlegt. Wenn sowohl ein Moniker als auch eine ProgID angegeben sind, wird die Instanz gesucht und mit der angegebenen Klasse gestartet – unabhängig davon, was in der Registrierungsdatenbank konfiguriert wurde. Soll die Datei durch eine andere als die in der Registrierungsdatenbank benannte Anwendung geöffnet werden, kann diese über die ProgID spezifiziert werden. Set o = GetObject("d:\buch\docs\test.xls") Set o = GetObject(, "Word.Application") Set o = GetObject("d:\buch\docs\test.xls", "Excel.Sheet") Listing 8.70: Beispiele zur Verwendung von GetObject() [com_getobject.vbs]
8.15.3
Verwendung von COM-Objekten
Die Verwendung von COM-Objekten entspricht der Arbeit mit Instanzen von VB-Klassen, d.h., die Objektvariable wird durch einen Punkt (.) von dem Mitgliedsnamen getrennt. Dies gilt sowohl für Attribute und Methoden als auch für Ereignisse. Zu beachten ist nur, dass nicht alle Scripting Hosts Ereignisse unterstützen und dass selbst die Scripting Hosts, die es können, nicht alle COM-Ereignisse behandeln können. Beherzigen Sie bei der Verwendung von Objektmodellen aus COM-Komponenten den Tipp, der auch schon für VB-Objekte gilt: Für jeden Punkt in einem Statement müssen einmal QueryInterface() oder – noch schlimmer – die IDispatch-Methoden GetIDsof Names() und Invoke() aufgerufen werden. Vermeiden Sie also die Angabe von tiefen Pfaden (Anweisungen mit mehreren Punkten).
8.15.4 Mehrere COMSchnittstellen
220
Verwendung von Mehrfachschnittstellen
Mehrfachschnittstellen sind unter COM ein wichtiges Thema. Ein Wechsel der Schnittstelle entspricht in der COM-Welt einem Aufruf von IUnknown::QueryInterface(). Da VBS nur IDispatch verwenden kann, bleibt die Welt der Mehrfachschnittstellen VBS auch hier vorenthalten. Das kann man positiv oder negativ sehen: Einerseits ist man von der
Nutzung von COM und DCOM
Komplexität der Mehrfachschnittstellen entlastet, andererseits kann VBS nur automationsfähige COM-Klassen nutzen und innerhalb dieser Klassen auch nur die Methoden, die über IDispatch bereitgestellt werden. Sind nicht alle Methoden aller benutzerdefinierten Schnittstellen auch in IDispatch einbezogen, bleibt VBScript ein Teil der Funktionalität verborgen. Anders bei VB 6.0/VBA: Dort stehen alle benutzerdefinierten Schnittstellen zur Verfügung. Ein expliziter Aufruf von QueryInterface() ist jedoch nicht vorgesehen. Er wäre zwar über einen direkten Aufruf der entsprechenden API-Funktion aus der COM-Bibliothek möglich – dieser schwierige Weg ist jedoch nicht nötig. VB ruft QueryInterface() immer dann neu auf, wenn eine Objektzuweisung an eine Objektvariable erfolgt. Zum Glück werden heute viele – aber leider nicht alle – COM-Klassen mit dualen Schnittstellen ausgestattet, die sowohl Aufrufe über IUnknown als auch über IDispatch unterstützen (vgl. Kapitel 7). Ausnahme: CDO 3.0 Mit CDO-Version 3.0 ist Microsoft einen anderen Weg gegangen, um Scriptsprachen den Umgang mit Mehrfachschnittstellen zu ermöglichen: Dort hat jede Schnittstelle eine eigene Implementierung von IDispatch und besitzt darüber hinaus eine Methode, die einen Zeiger auf eine andere Schnittstelle zurückliefern kann. So kann auch eine nicht vTable-fähige Sprache Mehrfachschnittstellen nutzen. Microsoft preist dieses Vorgehen als Vereinheitlichung der COM-Nutzung zwischen verschiedenen Sprachen (VB, C++, ...) an, allerdings auf Kosten der Konsistenz mit vielen anderen Komponenten.
Mehrfachschnittstellen beim Scripting
Der TypeOf-Operator Den Test, ob ein Objekt eine bestimmte Schnittstelle unterstützt, Schnittkönnen Sie nur unter VB 6.0/VBA durchführen. Eine Möglichkeit besteht darin, den Schnitt- stellenprüfung stellenwechsel mit Set zu versuchen und einen möglichen Fehler abzufangen. Eleganter ist die Verwendung des TypeOf-Operators, der sich durch das folgende Beispiel erklärt: Set o = New IWSHNetwork_Class say TypeName(o) ' IWSHNetwork2 If TypeOf o Is IWSHNetwork_Class Then MsgBox "IWSHNetwork_Class" ' Ja! If TypeOf o Is IWSHNetwork Then MsgBox "IWSHNetwork" ' Ja! If TypeOf o Is IWSHShell Then MsgBox "IWSHShell" ' Nein Listing 8.71: Testen einer Instanz auf die Unterstützung von Schnittstellen
8.15.5
Datentypprobleme beim Zugriff auf COM-Komponenten
In einigen Fällen kommt es bei der Verwendung von COM-Komponenten zu leichten Prob- Typprobleme lemen mit Datentypen: Wenn ein Attribut oder eine Methode in Form eines Parameters einen bestimmten Datentyp erwarten, werden sie mit dem VBS-Variant nicht immer glücklich sein.
221
8 Die Visual Basic-Sprachfamilie
Dazu ein Beispiel. Const FTPSERVER = "ftp://1.1.1.20" Set oiC = CreateObject("InetCtls.Inet") oiC.Execute FTPSERVER, "DIR" Do While oiC.StillExecuting DoEvents ' WScript.Sleep() Loop Listing 8.72: Ein Beispiel aus der Komponente „Microsoft Internet Control“
Obige Befehle werden problemlos ausgeführt. Wenn jedoch der Aufruf von Execute() und die darauf folgende Warteschleife gekapselt werden sollen, kommt es zu einem Fehler. Const FTPSERVER = "ftp://1.1.1.20" inet_doit oiC, FTPSERVER, "DIR" '--- Unterroutine Sub inet_doit(oiC, url, command) oiC.Execute url, command Do While oiC.StillExecuting DoEvents ' WScript.Sleep() Loop End Sub Listing 8.73: Dieses Script hat Probleme mit den Datentypen. [CD: /code/komponenten/INET/ inet_ ftp.vbs]
Durch die Übergabe der Zeichenkette an eine Unterroutine geht die Information verloren, dass es sich um einen Untertyp String handelt, so dass Execute() die angegebene URL als „falsch formatiert“ zurückweist. Abhilfe schafft in solchen Fällen eine explizite Typumwandlung, hier mit CStr(). oiC.Execute CStr(url), CStr(command)
8.16 Eingebaute Funktionen und Klassen Funktionen
Alle VB-Dialekte enthalten eine Reihe von eingebauten Funktionen für die Bereiche Mathematik, Zeichenkettenbearbeitung, Datum/Uhrzeit sowie Typkonvertierung. Eine Tabelle finden Sie in Anhang C.
Reguläre Ausdrücke
Außerdem bietet Visual Basic Script seit Version 5.0 eine eingebaute Klasse RegExp. Die Klasse wird nicht als Eingebautes Objekt bereitgestellt; der Programmierer muss sie selbst instanziieren. RegExp steht aber auch außerhalb von VBS als COM-Klasse VBScript.RegExp zur Verfügung.
8.17 Fehlerbehandlung On Error GoTo
222
Alle VB-Dialekte verfügen über eine Möglichkeit, Laufzeitfehler abzufangen. Diese ist in VB 6.0/VBA jedoch deutlich besser als in VBS. Grundlegende Anweisung ist On Error GoTo..., mit der festgelegt werden kann, dass das Programm im Fehlerfall nicht mit einer Fehlermeldung stehen bleiben, sondern an anderer Stelle weiterarbeiten soll.
Fehlerbehandlung
Befehl
Bedeutung
Unterstützung
On Error Resume Next Schaltet das Abfangen von Laufzeitfehlern ein, Alle VB-Dialekte
so dass misslungene Befehle übersprungen werden. Die Programmausführung macht dann beim nächsten Befehl weiter. On Error GoTo 0
Schaltet die Laufzeitfehlerbehandlung aus: Jeder Fehler führt wieder zum Abbruch.
Alle VB-Dialekte
Tabelle 8.18: Befehle zur Aktivierung bzw. Deaktivierung der Laufzeitfehlerbehandlung
Err-Objekt Nachdem Sie mit On Error GoTo... den Abbruch des Programms verhindert Fehlerinforhaben, können Sie über das eingebaute Objekt err (verfügbar in allen VB-Dialekten) Infor- mationen mationen über den Fehler erhalten. Das Eingebaute Objekt Err gehört zur Klasse ErrObject und verfügt u.a. über folgende Attribute: 왘 Err.Number: Fehlernummer des letzten aufgetretenen Fehlers 왘 Err.Description: textliche Beschreibung des Fehlers 왘 Err.Source: Quelle des Fehlers
Nach einem On Error Resume Next können Sie mit Err.Number feststellen, ob ein Fehler aufgetreten ist. On Error Resume Next MsgBox 1 / 0 If Err.Number 0 Then MsgBox "Fehler #" & Err.Number & " (" & Err.Description & _ ") ist in " & Err.Source & " aufgetreten." Err.Clear Else MsgBox "Befehl war erfolgreich!" End If Listing 8.74: Abfangen eines Fehlers [error_1.vbs]
Dieses Listing wird natürlich immer einen „Division durch Null“-Fehler melden. Nach einer Abfrage des Fehlers sollten Sie err.Clear() aufrufen, um anschließend nicht durcheinander zu kommen. Achtung: Wenn es zwischen der Überprüfung von Err.Number und der Ausgabe zu einem weiteren Fehler bzw. zu einem Folgefehler kommt, dann wird die eigentliche Fehlerinformation überschrieben. Sie können das Err-Objekt über seine Raise()-Methode auch dazu nutzen, selbst einen Fehler zu erzeugen. err.Raise(number, source, description)
Beispiel: err.raise "12345","Mein Skript","Nur ein Test-Fehler"
223
8 Die Visual Basic-Sprachfamilie
VB 6.0/VBA
Tabelle 8.19: Zusätzliche Befehle zur Behandlung von Laufzeitfehlern in VB 6.0/VBA
Beispiel
Fehlerbehandlung in VB 6.0/VBA Die Fehlerbehandlung in VBS ist etwas unbefriedigend, weil man im Prinzip nach jedem Befehl den Inhalt des Err-Objekts manuell auf möglicherweise aufgetretene Fehler überprüfen muss. VB 6.0/VBA können das besser. Befehl
Bedeutung
Unterstützung
On Error GoTo Marke
Springt im Fehlerfall zu der mit Marke: spezifizierten Markierung innerhalb des gleichen Unterprogramms
Nur VB 6.0/VBA
Resume
Fehlgeschlagenen Befehl erneut versuchen (nur innerhalb einer Fehlerbehandlungsroutine möglich)
Nur VB 6.0/VBA
Resume Next
Weiterarbeiten bei dem auf den fehlgeschlagenen folgenden Befehl (nur innerhalb einer Fehlerbehandlungsroutine möglich)
Nur VB 6.0//VBA
Resume Marke
Weiterarbeiten bei Marke: (nur innerhalb einer Fehlerbehandlungsroutine möglich)
Nur VB 6.0//VBA
Die nachstehende Routine MachEinenFehler() definiert nach Fehler: eine Fehlerbehandlungsroutine. Dabei besteht die Wahl, den fehlerverursachenden Befehl mit Resume Next zu überspringen oder aber (nach Beseitigung der Fehlerursache) den gleichen Befehl erneut zu versuchen (Resume). Eine derartige Fehlerbehandlungsroutine pro Unterroutine genügt. Man muss nur auf eins achten: Da die Fehlerbehandlungsroutine keine wirklich eigenständige Routine, sondern ein Teil der Gesamtroutine ist, muss mit einem Exit Sub verhindert werden, dass die Programmausführung zwangsläufig in den Fehlerbehandlungsteil läuft. x = 1 y = 0 On Error GoTo Fehler: MsgBox x / y Exit Sub 'Nicht vergessen! ' --- Fehlerbehandlung Fehler: MsgBox "Fehler #" & Err.Number & " (" & _ Err.Description & ") ist in " & Err.Source & " aufgetreten." a = MsgBox("Nochmal versuchen?", vbYesNo, "Frage") If a = vbYes Then y = 1 Resume Else Resume Next End If Listing 8.75: Beispiel zur Fehlerbehandlung (nur VB 6.0/VBA) [error_2.vbs]
224
Allgemeine Hilfsroutinen
8.18 Allgemeine Hilfsroutinen Einige Hilfsroutinen werden Ihnen in den Beispielen immer wieder begegnen. Diese seien hier am Anfang zusammengestellt. Sie bilden die Funktionsbibliothek WS_scriptLIB [CD:/code/sprachen/_bibliotheken /WS_scriptL IB.vbs].
WS_scriptLIB
Sie können den Quelltext dieser Bibliothek in Ihre eigenen Scripts kopieren oder aber – besser – in Ihre eigenen Scriptdateien als externe Datei einbinden. Für die Scripting Hosts, die keine eigene Routine zur Einbindung liefern, wird im nächsten Unterkapitel eine Lösung vorgestellt. Einige der Routinen der WS_ScriptLIB sind auch in der Klasse Util der COMKomponente WindowsScripting enthalten.
8.18.1
Scripteinbindung
Nicht alle Scripting Hosts unterstützen die Einbindung externer Scriptdateien. In diesen Scripting Hosts müssten Sie also Funktionsbibliotheken extern immer durch Cut&Paste im Quellcode in Ihre Scripts übernehmen. Mit Hilfe der ExecuteGlobal()-Methode aus VBS 5.0 und der in Kapitel 10.2 vorgestellten Scripting Runtime-Komponente zum Dateisystemzugriff kann man sich jedoch eine eigene Einbindungsroutine bauen. Die in Listing 8.76 gezeigte Funktion Include() öffnet die einzubindende Scriptdatei mit Hilfe der Klasse Scripting.TextStream aus der Scripting Runtime-Komponente und führt den eingelesenen Quellcode dann mit ExecuteGlobal() aus. Auf Grund der Eigenschaft von ExecuteGlobal(), alle enthaltenen globalen Variablen und Unterroutinen im globalen Namensraum des aufrufenden Script zur Verfügung zu stellen (vgl. Kapitel 8.13), eignet sich Include() also, um Funktionsbibliotheken einzubinden. Im Fehlerfall werden die Fehlerinformationen als Zeichenkette zurückgegeben.
Include()Funktion für alle Scripting Hosts
' == Universelle Einbindung externer Skriptdateien Function Include(skriptname) dim fso ' As Scripting.FileSystemObject dim oTX ' As Scripting.TextStream On Error Resume Next Set fso = CreateObject("Scripting.FileSystemObject") If fso.FileExists(skriptname) Then Set oTX = fso.OpenTextFile(skriptname) ExecuteGlobal oTX.ReadAll If Err.Number 0 Then ' Fehler Include = Err.Number & ":" & Err.Description Else ' kein Fehler Include = "" End If oTX.Close Else ' Datei nicht gefunden Include = "Datei existierte nicht!" End If End Function Listing 8.76: Include-Funktion für alle Scripting Hosts [CD: /code/sprachen/_bibliotheken / WS_ScriptLIB.vbs]
Diese Routine läuft nicht in VB 6.0/VBA!
225
8 Die Visual Basic-Sprachfamilie
Diese Routine ist die einzige, die Sie in den Quelltext jedes Ihrer Scripts duplizieren müssen. Alle anderen Routinen können Sie zentral in Dateien speichern und mit Include() einbinden.
8.18.2 Flat()
Umwandlungsroutinen
Eine hilfreiche Funktion, die Sie immer wieder dann brauchen werden, wenn Attribute fallweise entweder einen elementaren Wert oder ein Array zurückgeben, ist flat(). Diese Hilfsroutine überprüft, ob der übergebene Wert ein Array ist. Wenn dies zutrifft, wird aus dem Array eine durch Semikola getrennte Zeichenkette erzeugt. flat() bedient sich der Hilfsroutine CSVadd(), die eine Zeichenkette durch ein Semikolon getrennt an einen andere Zeichenkette anhängt. Die Gesamtzeichenkette wird bewusst sowohl durch einen Referenzparameter (Call by Reference) im ersten Parameter als auch über den Rückgabewert zurückgegeben; dies gibt dem Nutzer der Routine mehr Flexibilität in ihrem Gebrauch. Das Semikolon wird ausgelassen, wenn die erste Zeichenkette noch leer war. Function flat(var) ' On Error Resume Next Dim i ' As Integer If IsArray(var) Then flat = Join(var, Else flat = var End If End Function
As String
' Array flachklopfen ";") ' War kein Array
Listing 8.77: Macht aus einem Array eine CSV-Zeichenkette. [CD: /code/sprachen/_bibliotheken / WS_ScriptLIB.vbs]
8.18.3 Umwandlung numerischer Konstanten in Zeichenketten
Rückumwandlung von Konstanten
Komponenten arbeiten in der Regel nicht mit symbolischen, sondern mit numerischen Konstanten. Eine Definition der Form Const SymbolischerName = Wert bietet dem Entwickler aber nur Unterstützung beim Setzen von Werten: Er kann bei der Wertzuweisung den symbolischen Konstantennamen statt eines numerischen Werts verwenden. Wenn jedoch eine Instanz einer Klasse einen numerischen Wert (zurück-)liefert, dann helfen die Const-Definitionen nicht, daraus eine symbolische Konstante oder einen sprechenden Begriff in Form einer Zeichenkette zu machen. Auf Basis von Typbibliotheken gibt es Möglichkeiten, den symbolischen Konstantennamen zur Laufzeit durch das Auslesen der Typbibliothek zurückzugewinnen (vgl. [WES99a]). Dies ist jedoch entweder codeintensiv oder erfordert die Zusatzinstallation einer Komponente, die die Rückübersetzung kapselt. Außerdem funktioniert das Verfahren nur mit Typbibliotheken. In diesem Buch wird daher ein anderer, einfacherer Ansatz gewählt. Parallel zu den Konstantendefinitionen werden zweidimensionale Arrays für die Konstantenlisten angelegt, wobei die erste Spalte jeweils den symbolischen Namen und die zweite Spalte den Wert enthält. Mit Hilfe der Routine get_from_array(wert, feld) wird aus einem bestimmten Feld anhand eines übergebenen Werts der passende symbolische Name herausgesucht. Da es auch Flags gibt, bei denen ein numerischer Wert mehrere symbolische Namen
226
Allgemeine Hilfsroutinen
repräsentiert, existiert auch die Variante get_from_array_mult(wert, feld), die durch eine bitweise Und-Verknüpfung alle Teilwerte ermittelt, aus denen ein Gesamtwert besteht. Die Eingabe des zur Füllung der Arrays nötigen Programmcodes kann sehr mühsam sein. Dabei unterstützt Sie der mit diesem Buch mitgelieferte comTLBrowser (siehe Kapitel 18 „Werkzeuge“): Er erzeugt aus einem Aufzählungstyp in einer Typbibliothek den passenden Code, um ein Array so zu füllen, dass mit get_from_array() bzw. get_from_array_mult() eine Rückumwandlung möglich ist. Der große Vorteil der Array-Methode ist, dass Sie die symbolischen Namen beliebig ändern können. Beim Zugriff auf die Typbibliothek bekommen Sie immer nur die dort definierten symbolischen Namen. ' ### Entnimmt aus einem zweidimensionalen Array einen passenden Wert ' ### Ermittelt Wert von Spalte1 anhand eines Wertes aus Spalte2 Function Get_From_Array(wert, feld) Dim i ' As Integer get_from_array = "n/a" ' -- Über alle Zeilen im Feld For i = LBound(feld, 1) To UBound(feld, 1) If feld(i, 1) = wert Then ' gefunden! get_from_array = feld(i, 0) Exit For End If Next End Function ' ### Entnimmt aus einem zweidimensionalen Array passende Werte ' ### Ermittelt Werte von Spalte1 anhand eines Wertes aus Spalte2 Function get_from_array_mult(wert, feld) Dim i ' As Integer get_from_array_mult = "" ' -- Über alle Zeilen im Feld For i = LBound(feld, 1) To UBound(feld, 1) If feld(i, 1) And wert Then If get_from_array_mult "" Then _ get_from_array_mult = get_from_array_mult & ";" end if get_from_array_mult = get_from_array_mult & feld(i, 0) End If Next End Function Listing 8.78: Standardroutinen zur Umwandlung einer numerischen Konstante in eine Zeichenkette
8.18.4
Ausgabe
Ein guter Scriptprogrammierer kapselt alle Ausgaben in Unterroutinen, um die Scripts schnell an die Scripting Host-spezifischen Ausgabeweisen anpassen zu können. Zentral ist die Routine say(), die eine übergebene Zeichenkette ausgibt. Say() ist nicht Bestandteil der
227
8 Die Visual Basic-Sprachfamilie
WS_ScriptLIB, da say() hostspezifisch ist und damit nicht den host-neutralen Anspruch der WS_ScriptLIB erfüllt. Die WS_ScriptLIB liefert jedoch einige Routinen, die auf say() aufbauen, und erwartet also, dass das Hauptprogramm oder eine andere Bibliothek say() implementiert. Sie werden in Kapitel 9 einige hostspezifische Bibliotheken (WS_AspLIB, WS_VbWSHLIB, WS_ExAgLIB) finden, die dieser Anforderung gerecht werden. sayerror ()
Fehlerausgabe Hilfreich ist eine Routine, die neben der übergebenen Zeichenkette auch den Zustand des Err-Objekts ausgibt. Sub sayerror(s) say "FEHLER: " & Err.Number & _ " (" & Err.Description & "): " & s End Sub Listing 8.79: Ausgabe eines Fehlers
saydebug ()
Bedingte Ausgabe während des Debugging Sie sollten berücksichtigen, dass Sie zur Entwicklungs- und Testzeit mehr Ausgaben benötigen als später im produktiven Einsatz. Dies können Sie über eine globale Konstante mit Namen DEBUGMODE steuern. Saydebug() macht nur eine Aussage, wenn dieser DEBUGMODE auf True gesetzt wurde. Const DEBUGMIODE = True Sub saydebug(s) If DEBUGMODE Then say s End Sub Listing 8.80: Bedingte Ausgabe (nur im Debugmodus)
sayex ()
Ausführliche Ausgabe Sayex() ist eine erweiterte Ausgabefunktion, die Ausgaben laufend durchzählt und zusammen mit Datum und Uhrzeit ausgibt. Dazu werden zwei globale Variablen benötigt. Die Möglichkeit statischer lokaler Variablen mit dem Schlüsselwort Static gibt es nur in VB 6.0/VBA. Dim sayall ' As String Dim saycount ' As Integer Sub sayex(s) On Error Resume Next Dim text ' As String saycount = saycount + 1 text = saycount & ". (" & Now & "): " & s sayall = sayall & text & vbCr & vbLf say text End Sub Listing 8.81: Ausführliche Ausgabe
8.18.5 WriteTo()
228
Schreiben in eine Log-Datei
Dem Schreiben von Logs in Textdateien dient die Routine WriteTo(FilePath, Text). WriteTo() hängt den übergebenen Text an die bezeichnete Datei an. Die verwendeten COM-Klassen werden in Kapitel 10.2 erläutert.
Allgemeine Hilfsroutinen
' ### Anhängen einer Zeichenkette an eine Datei Sub WriteTo(FilePath, Text) Dim oTX ' As Scripting.TextStream Dim FSO ' As Scripting.FileSystemObject On Error Resume Next Set FSO = CreateObject("Scripting.FileSystemObject") Set oTX = FSO.OpenTextFile(FilePath, 8, True) ' 8 = ForAppending oTX.WriteLine Text oTX.Close On Error GoTo 0 End Sub Listing 8.82: Anhängen von Text an eine Protokolldatei
8.18.6
Fehlerüberprüfung
Wenn Sie die Fehlerüberprüfung mit On Error Resume Next ausgeschaltet haben, dann Check() müssen Sie selbst regelmäßig den Status des Err-Objekts abfragen. Dies können Sie an eine Hilfsroutine delegieren, die Sie an zentralen Stellen in Ihren Scripts (Prüfpunkte) aufrufen. Eine von Ihnen übergebene Information über den zuletzt ausgeführten Vorgang wird bei der Protokollierung berücksichtigt. Function Check(strStep) ' As Boolean If Err.Number 0 Then sayerror strStep Err.clear check = True Else If DEBUGMODE Then say "STEP OK: " & strStep check = False End If End Function Listing 8.83: Überprüfung, ob ein Fehler aufgetreten ist
8.18.7
COM-Funktionen
Sehr hilfreich sind Funktionen, die überprüfen, ob eine bestimmte Instanz existiert (per ExistsZugriff über einen Moniker) oder ob eine bestimmte Klasse instanziiert werden kann (per Object() ProgID oder CLSID). ' ### Existiert eine COM-Instanz? Function existsObject(moniker) ' As Boolean Dim obj ' As Object On Error Resume Next Set obj = GetObject(moniker) If obj Is Nothing Then ExistsObject = False Else ExistsObject = True End If
229
8 Die Visual Basic-Sprachfamilie
Err.Clear On Error GoTo 0 End Function ' ### Testet, ob COM-Objekt mit CreateObject() instanziiert werden kann Function checkCreate(progid) ' As Boolean Dim obj ' As Object On Error Resume Next Set obj = CreateObject(progid) If obj Is Nothing Then CheckCreate = False Else CheckCreate = True End If Err.Clear On Error GoTo 0 End Function Listing 8.84: COM-Hilfsroutinen GetCol()
Ausgabe von Objektmengen Bei der Erforschung von Komponenten wollen Sie häufig wissen, welche Objekte eine Objektmenge (Collection) enthält. Die folgende Hilfsroutine GetCol() liefert eine durch Semikolon getrennte Liste der Namen der Unterobjekte. Die Hilfsroutine funktioniert aber nur, wenn die Objekte in der Objektmenge ein Attribut Name besitzen. Function GetCol(objcol) Dim o ' As Object For Each o In objcol CSVadd getCol, o.Name Next End Function Listing 8.85: CSV-Liste der Elemente einer Objektmenge/eines Containers
sayCol() sayCol() gibt Informationen zu einer Objektmenge aus. Dabei sind die Abfrage des
Namens der Objektmenge und der Zugriff auf das Count-Attribut bewusst fehlertolerant ausgelegt, da nicht alle Objektmengen diese Fähigkeiten besitzen. Zur Ausgabe einer Liste der Unterobjekte wird die von GetCol() gelieferte CSV-Liste in eine durch Zeilenumbrüche getrennte Liste umgewandelt. Sub sayCol(objcol) Dim s ' As String On Error Resume Next say "Objektmenge: " & objcol.Name say "Anzahl Objekte: " & objcol.Count On Error GoTo 0 s = GetCol(objcol) say Replace(s, ";", Chr(13)) 'Zeilenumbruch statt Semikolon End Sub Listing 8.86: Universelle Ausgabe einer Objektmenge/eines Containers
230
Allgemeine Hilfsroutinen
Schöner wäre es, diese Routine noch etwas allgemeiner zu halten und auch das auszuge- GetColEX() bende Attribut variabel zu gestalten. Leider gibt es dafür keine Lösung, die in allen VB-Dialekten gleichermaßen funktioniert. VB 6.0/VBA bieten die Funktion CallByName(), mit der auf ein Attribut bzw. eine Methode zugegriffen werden kann, deren Name in Form einer Zeichenkette übergeben wird. Sub GetColEX(objcol, attribut) Dim o ' As Object For Each o In objcol CSVadd getColex, CallByName(o, attribut, VbGet) Next End Sub Listing 8.87: Erweiterte Version von getCol() (nur VB 6.0/VBA)
Unter VBS gibt es CallByName() nicht; hier kann das eval-Statement verwendet werden. Function GetColEX(objcol, attribut) ' As String Dim o ' As Object For Each o In objcol CSVadd getColex, eval("o." & attribut) Next End Function Listing 8.88: Erweiterte Version von getCol() (nur VB 6.0/VBA)
Wenn Sie nicht wissen, ob es ein Element in einer Objektmenge gibt, dann hilft Ihnen dieser GetItem() fehlertolerante Zugriff auf ein durch einen Schlüssel spezifiziertes Unterobjekt. Function GetItem(Item, Key) ' As Variant getItem = "" On Error Resume Next getItem = Item(Key) End Function Listing 8.89: Fehlertoleranter Zugriff auf ein Element einer Objektmenge
231
9
Die Scripting Hosts
Dieses Kapitel stellt Ihnen verschiedene Active Scripting Hosts vor. Da die Scripting Hosts Einführung anderer Anbieter einen vergleichsweise geringen Verbreitungsgrad haben, liegt der Schwer- in die Scripting Hosts punkt auf den Scripting Hosts von Microsoft. An einigen Stellen ist der Scripting Host ganz offensichtlich, an anderen Stellen verbirgt er sich im tiefen Inneren einer größeren Anwendung. Um Ihnen diese Scripting Hosts zu erläutern, ist eine – wenn auch knappe – Einführung in die Umgebung des Host unerlässlich. Im Kapitel „Fortgeschrittene Techniken“ werden Ihnen dann mit VBA und Visual Basic 6 auch zwei Umgebungen vorgestellt werden, die keine Active Scripting Hosts, aber hinsichtlich der Entwicklung von Automatisierungslösungen ähnliche, wenngleich mächtigere Umgebungen sind.
Ausblick
Unterscheidungskriterien Die Active Scripting Hosts unterscheiden sich vor allem in Merkmale der Scripdrei Punkten:
ting Hosts
왘 Speicherung der Scripts 왘 Komplexität 왘 Ein- und Ausgabebefehle
Speicherform Ein Script kann entweder in einer eigenständigen (Text-)Datei angelegt Dateien werden oder aber in eine andere (Text-)Datei eingebettet sein. Eingebettete Script findet und andere Medien man in der überwiegenden Zahl der Hosts. Eigenständige Dateien verwendet beispielsweise der Windows Script Host. Neben Dateien sind aber auch andere Speicherorte vorzufinden: Der Exchange Server speichert Ereignisscripts in Nachrichten im Message Store, der SQL Server-Agent in einer Systemdatenbank. Diese Scripts können natürlich nur über die entsprechenden Rahmenanwendungen bearbeitet werden. Komplexität Die Komplexität und damit auch die Bedienungsfreundlichkeit ist in den BedienungsScripting Hosts sehr verschieden. Die Unterschiede liegen vor allem darin, wie man ein freundlichkeit Script an den Host übergibt, wie man Rückmeldungen des Script empfängt und in welcher Form das Debugging stattfindet. Der Windows Script Host (WSH) ist der einfachste Host, wie Sie an der schnellen Erstellung Ihres ersten Script in Kapitel 6 gesehen haben. Etwas komplizierter sind bereits Internet Explorer und ASP, weil die Scripts hier korrekt in HTML-Seiten eingebaut werden müssen. Sehr komplex sind das SQL Server Job Scripting und der Exchange Event Service, weil keine Bildschirmausgaben möglich sind.
233
9 Die Scripting Hosts
Ein- und Ausgabe
Ein- und Ausgabe Die Unterschiede bei den Ein- und Ausgabebefehlen sind groß, da diese auf den Eingebaute Objekte beruhen. So ist der Zugriff auf die an ein ASP-Script übergebenen Parameter vollkommen anders als auf die E-Mail, die ein Exchange Event Agent getriggert hat. Während dies noch nachzuvollziehen ist, könnte es bei den Ausgabebefehlen eine Vereinheitlichung geben: Zurzeit erzeugt man Ausgaben im WSH mit WScript.Echo(), in ASP mit Response.Write(), im Internet Explorer mit Document.Write() und im Exchange Event Agent gar nicht über eine Methode, sondern über eine Wertzuweisung an das Attribut Script.Response.
say()
Ein guter Tipp an dieser Stelle ist es, alle Ausgaben in eine eigene Unterroutine zu kapseln; beim späteren Wechsel des Scripting Host ist dann nur an einer zentralen Stelle eine Änderung nötig. In diesem Buch werden Sie bei der Beschreibung der Komponenten in der Regel als Ausgabebefehl nur say() finden. say() ist in keiner der heute verfügbaren Sprachen oder Scripting Hosts vordefiniert. say() ist der Name der Kapselungsfunktion nach dem oben geschilderten Prinzip. In saynb() steht nb für No Break und ist eine Version von say(), in der nach der Angabe kein automatischer Zeilenumbruch erfolgt. Das ist nur in einigen Umgebungen möglich; meistens erzeugen die Ausgabebefehle automatisch einen Zeilenumbruch.
Tabelle 9.1: say() in verschiedenen Scripting Hosts
Scripting Host
Gekapselte Ausgabefunktion(en)
Name der Funktionsbibliothek
Internet Explorer / Vista Sidebar Gadgets
Sub saynb(s) Document.Write s End Sub
WS_ieLIB.vbs
Sub say(s) Document.Write s & "" End Sub
Active Server Pages (ASP)
Sub saynb(s) Response.Write s End Sub
WS_aspLIB.vbs
Sub say(s) Response.Write s & "" End Sub
Event Scripting Agent
Sub say(s) Script.Response = _ Script.Response & chr(13) & s End Sub
Windows Script Host (WSH) Sub say(s) WScript.Echo s End Sub
234
WS_exagLIB.vbs
WS_vbwshLIB.vbs
Scripting Host
Gekapselte Ausgabefunktion(en)
Name der Funktionsbibliothek
Microsoft Outlook Forms
Es gibt keine spezifische Ausgabefunktion. Ausgaben können entweder über die Steuerelemente in Outlook Forms oder aber über sprachspezifische Ausgabemethoden (z.B. MsgBox()) erfolgen.
Keine
Sub say(s) MsgBox s End Sub
SQL Server Job Scripting
Sub say(s) SQLActiveScriptHost.Print(s) End Sub
Keine
Data Transformation Service (DTS)
Es gibt keine spezifische Ausgabefunktion. Ausgaben können nur über sprachspezifische Ausgabemethoden (z.B. MsgBox()) erfolgen.
Keine
Sub say(s) MsgBox s End Sub Sub say(ausgabe) Visual Basic 6.0 und VBA (Ausgabe im Debug-Fenster) Debug.Print ausgabe
WS_vbwshLIB.vbs
End Sub
Visual Basic 6.0 und VBA (Ausgabe als Dialogfenster)
Sub say(ausgabe) MsgBox ausgabe Sub
Keine
Visual Basic .NET (Ausgabe im Debug-Fenster)
Sub say(ausgabe) Debug.Writeline(ausgabe) End Sub
Keine
Visual Basic .NET (Ausgabe an der Kommandozeile)
Sub say(ausgabe) Console.Writeline(ausgabe) End Sub
Keine
Visual Basic .NET (Ausgabe als Dialogfenster)
Sub say(ausgabe) MsgBox(ausgabe) End Sub
Keine
Script Control
Hier kann man die eingebauten Objekte und die Ausgabefunktion individuell implementieren.
Keine
Einige Scripting Hosts (z.B. ASP, SQL Server Agent, Exchange Event Agent) sind darauf aus- Keine Dialoggelegt, als unbeaufsichtigte Serveranwendung zu laufen. Sie unterstützen keine Ausgabe von fenster Dialogfenstern (z.B. mit den VB-Befehlen MsgBox() oder InputBox()) und von anderen Bildschirmelementen zur direkten Interaktion mit dem Benutzer.
235
9 Die Scripting Hosts
Funktionsbibliotheken Dieses Buch liefert Ihnen zu einigen Scripting Hosts vom Autor erstellte Funktionsbibliotheken. Darin ist auch say() definiert. Wenn Sie ein Script zwischen zwei Scripting Hosts portieren wollen, müssen Sie manchmal nur die Funktionsbibliothek austauschen. Im Fall von VB 6.0/VBA und dem WSH ist nicht einmal das nötig: Die Bibliothek ist darauf ausgelegt, in beiden Umgebungen zu arbeiten. Es müssen lediglich einzelne Zeilen aktiviert bzw. deaktiviert werden. Der Sinn dieser gemeinsamen Bibliothek liegt in der Verwendung von VB 6.0/VBA als Prototypumgebung für WSHScripts. Dies wird im Kapitel 19 „Fortgeschrittene Active Scripting-Techniken“ näher beschrieben werden. In der Regel beruhen die Funktionsbibliotheken auf der WS_ScriptLIB, die im Kapitel zu Visual Basic beschrieben wurde. Letztere müssen Sie also auch mit einbinden.
9.1 WSH
Windows Script Host (WSH)
Der Windows Script Host (WSH) ist der Scripting Host, der direkt auf dem Betriebssystem ausgeführt wird. Außer dem Scripting Host (zwei EXE-Dateien) und den zugehörigen DLLs ist keine weitere (BackOffice-)Anwendung notwendig. Der WSH ist daher der unkomplizierteste Scripting Host. Andererseits ist er der komplexeste, weil er viele Funktionen (z.B. XML-Strukturierung, COM-Ereignisbehandlung) bietet, die in anderen Scripting Hosts (noch) nicht verfügbar sind. Im Englischen werden Abkürzungen gerne mit Vokalen aufgefüllt, um sie aussprechen zu können. Insider nennen den WSH daher liebevoll „Wish“. Oft wird WSH mit dem allgemeinen Begriff Scripting Host gleichgesetzt. Dies ist jedoch nicht korrekt: Der WSH ist nur einer von vielen Scripting Hosts gemäß der Windows Scripting-Architektur.
9.1.1 Kuriose Versionszählung
Verfügbare Versionen
Microsoft bietet inzwischen die dritte Version des WSH an. Zwischen Version 1.0 und Version 2.0 hat Microsoft eine kleine, aber entscheidende Namensänderung von Windows Scripting Host zu Windows Script Host vollzogen, die wohl der Abgrenzung zwischen dem allgemeinen Begriff Scripting Host und dem WSH dienen soll. Die Versionsnummer der dritten Version des WSH verwundert: Das Microsoft-Einmaleins geht so: 1.0, 2.0, 5.6, 5.7. Aber es gibt eine Erklärung: Schon der WSH 1.0 verstand sich intern als Version 5.0. Der WSH 2.0 antwortete auf eine Anfrage nach seiner Versionsnummer mit „WSH 5.5“. Jetzt hat Microsoft dieses Kuriosum aufgelöst: Das Produkt hat intern und extern die gleiche Versionsnummer. Die aktuellste WSH-Version ist zum Redaktionsschluss dieses Buchs die Version 5.7.0.5600 in Windows Vista Release Candidate 1. Die nachfolgende Tabelle zeigt die Verfügbarkeit des WSH für die 32-Bit-Windows-Systeme.
236
Windows Script Host (WSH)
Betriebssystem
WSH-Verfügbarkeit
Windows 95
WSH nicht enthalten; WSH 1.0, 2.0 oder 5.6 können nachträglich installiert werden
Windows 98
WSH 1.0; Aktualisierung auf 2.0 oder 5.6 möglich
Windows ME
enthält WSH 2.0; Aktualisierung auf 5.6 möglich
Windows NT 4.0
WSH nicht enthalten; WSH 1.0, 2.0 oder 5.6 können nachträglich installiert werden
Windows 2000
enthält WSH 2.0; Aktualisierung auf 5.6 möglich
Windows XP
enthält WSH 5.6 (Version 5.6.6626); Aktualisierung auf Version 5.6.8525 möglich
Windows Server 2003
enthält WSH 5.6 (Version 5.6.8515)
Windows Vista
enthält WSH 5.7
Windows Preinstallation Environment (WinPE)
enthält WSH 5.6
Tabelle 9.2: Verfügbarkeit des WSH in verschiedenen Betriebssystemversionen
Vermittlung der WSH-Version per WSH-Script Der WSH kann mit einem Einzei- Versionsler getestet werden. Das Attribut Version aus dem Eingebauten Objekt WScript enthält die ermittlung Versionsnummer. Das Codebeispiel ist in VBS geschrieben. Erstellen Sie eine Textdatei mit der Erweiterung .vbs und hinterlegen Sie dort den nachfolgenden Code. Starten Sie das Script dann per Doppelklick. ' WSH-Test-Skript (VBS) WScript.Echo "Dies ist der " & WScript.Name & _ " Version " & WScript.Version Listing 9.1: Ausgabe der Versionsnummer des WSH [WSH_test.vbs]
Neue Funktionen im WSH 2.0 Gegenüber dem WSH 1.0 bietet der WSH 2.0 folgende Features im WSH 2.0 neue Möglichkeiten bzw. Verbesserungen: 왘 XML-Strukturierung der Dateien 왘 Mehrere Scripts pro Datei 왘 Mehrere Sprachen pro Script 왘 Einbindung anderer Scriptdateien 왘 Einbindung von Typbibliotheken 왘 Drag&Drop-Unterstützung 왘 In dem eingebauten Objekt WScript wurde Folgendes verbessert: 왘 Warteschleife mit Sleep() 왘 Zugriff auf Standard-I/O-Kanäle (StdIn, StdOut, StdErr)
Weitere Ergänzungen beziehen sich auf die WSH Runtime Library, die in Kapitel 10.1 besprochen wird.
237
9 Die Scripting Hosts
WSH 5.6
Neue Funktionen im WSH 5.6 Die Neuerungen im WSH 5.6 sind: 왘 Digitale Signierung von Scripts (siehe Kapitel 19 „Fortgeschrittene Techniken“) 왘 Entfernte Ausführung von Scripts (siehe Kapitel 19 „Fortgeschrittene Techniken“) 왘 Selbstbeschreibende Parameter für XML-strukturierte WSH-Dateien (erläutert in die-
sem Kapitel) Signierung Der Autor dieses Buchs freut sich, dass Microsoft mit den digital signierten Scripts genau
das realisiert hat, was er in einem früheren Beitrag zur Scripting-Sicherheit [SCH00c] gefordert hat. Neue Funktionen im WSH 5.7 Für die in Windows Vista enthaltene Version 5.7 des Windows Script Host sind leider bis zum Redaktionsschluss dieses Buchs keine Funktionslisten oder Dokumentation verfügbar. Auf den ersten Blick und auch nach Inspektion der Typbibliotheken sind keine neuen Funktionen erkennbar.
9.1.2
WSH-Installation
Optionen zur Das Setup zum WSH 2.0 und zum WSH 5.6 finden Sie auf der Buch-CD [CD:/install/hosts/ unbeaufsich- WSH]. Die jeweils aktuelle Version des WSH kann von der Microsoft Scripting Website tigten Installation [MSS00] bezogen werden. Das Setup besteht jeweils aus einer einzigen Datei. Diese Installa-
tionsroutine bietet einige Kommandozeilenoptionen für die unbeaufsichtigte Installation. Das ist hilfreich, wenn man den WSH über ein DOS-Batch-Login-Script oder einen Auftrag im Microsoft System Management Server (SMS) automatisiert an Workstations von Endbenutzern verteilen möchte. Die Installation des WSH ist dann hoffentlich die letzte BatchDatei, die Sie erstellen mussten; in Zukunft können Sie den Anwendern WSH-Scripts liefern. Tabelle 9.3: Kommandozeilenoptionen des WSH-Setup
Option Bedeutung /q
Softwarelizenzvertrag wird vor der Installation nicht angezeigt.
/q:a
Softwarelizenzvertrag wird vor der Installation nicht angezeigt und die Fortschrittsanzeige unterbleibt. Der Anwender hat daher keinen Zugriff auf die Abbruch-Schaltfläche und kann die Installation nicht verhindern.
/r:s
Wenn ein Neustart nötig ist, wird dieser ohne Nachfrage durchgeführt.
/r:n
Ein Neustart wird auf keinen Fall durchgeführt.
9.1.3 Registrierungsdatenbank
WSH-Konfiguration
In der Registrierungsdatenbank gibt es Konfigurationseinträge für den WSH. Die Einträge befinden sich unterhalb folgender Schlüssel: 왘 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Script Host 왘 HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Scripting Host 왘 HKEY_CURRENT_USER\Software\Microsoft\Windows Script 왘 HKEY_CURRENT_USER\Software\Microsoft\Windows Script Host
238
Windows Script Host (WSH)
Systemweite vs. benutzerspezifische Einstellungen Wie an den Schlüsselnamen zu erkennen ist, gibt es sowohl systemweite als auch benutzerspezifische Einstellungen. Der Eintrag HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ Windows Script Host\Settings\ IgnoreUserSettings legt fest, ob die benutzerspezifischen Einstellungen die systemweiten Einstellungen überlagern dürfen oder ob die benutzerspezifischen Einstellungen ignoriert werden.
Benutzerspezifische Einstellungen deaktivieren
Bild 9.1: Systemweite Einstellungen für den WSH
Bild 9.2: Systemweite Einstellungen für die Dateierweiterungen
Bild 9.3: Benutzerspezifische Einstellungen
239
9 Die Scripting Hosts
Bild 9.4: Weitere benutzerspezifische Einstellungen
Tabelle 9.4: WSH-Konfiguration in der Registrierungsdatenbank
Eintrag
Erläuterung
ActiveDebugging
Bei Fehlern wird der Debugger gestartet. (0 = Nein, 1 = Ja)
DisplayLogo
Bestimmt, ob beim Start von CScript.exe an der Kommandozeile ein Vorspann mit dem Namen und der Version des Scripting Host ausgegeben wird. (0 = Nein, 1 = Ja)
Enabled
Deaktivierung des WSH (0 = WSH deaktiviert, 1 = WSH aktiviert)
IgnoreUserSettings
Bestimmt, ob die benutzerspezifischen Einstellungen die systemweiten Einstellungen überlagern. (0 = Ja, 1 = Nein)
LogSecurityFailures
Legt fest, ob erfolglose Versuche, ein Script zu starten, protokolliert werden sollen. Grund für erfolglose Versuche sind die Deaktivierung des WSH mit dem Eintrag Enabled sowie die Einstellung für digital signierte Scripts (TrustPolicy). (0 = Nein, 1 = Ja)
LogSecuritySuccesses Legt fest, ob erfolgreiche Scriptstarts protokolliert werden sollen. (0 = Nein, 1 = Ja)
240
Remote
Bestimmt, ob ein anderer Rechner Scripts auf diesen Rechner übertragen und hier ausführen darf. (0 = Nein, 1 = Ja)
TrustPolicy
Einstellung für die digital signierten Scripts: 0 ist die Standardeinstellung und bedeutet, dass alle Scripts laufen. 1 lässt dem Benutzer bei unsignierten Scripts die Wahl. 2 bedeutet, dass grundsätzlich die Ausführung aller Scripts unterbunden wird, die unsigniert sind, deren Integrität verletzt ist oder bei denen es Unzulänglichkeiten hinsichtlich der Zertifizierungsstellen oder der Vertrauenskette gibt.
Windows Script Host (WSH)
Eintrag
Erläuterung
TimeOut
Anzahl der Sekunden, nach denen ein Script automatisch beendet wird
UseWINSAFER
Legt fest, ob die Software Restriction Policies (SRP) auf WSHScripts angewendet werden sollen (vgl. Unterkapitel zur WSH-Sicherheit) (0 = Nein, 1 = Ja)
Das Setup des WSH 5.6 legt alle Einträge mit dem Registrierungsdatenbank-Datentyp REG_SZ an. Einige dieser Einträge (z.B. Remote und TrustPolicy) benötigen aber in Wirklichkeit den Typ REG_DWORD. Wenn eine Änderung eines Registrierungsdatenbankeintrags keine Wirkung hat, sollten Sie den Eintrag löschen und als REG_DWORD neu anlegen. Den WSH deaktivieren Mit dem Eintrag HKEY_LOCAL_MACHINE\SOFTWARE\Micro- Enabled soft\Windows Script Host\Settings\Enabled lässt sich der WSH deaktivieren. Wenn dieser Eintrag auf 0 steht, kann kein WSH-Script ausgeführt werden. Ein Aufruf von CScript.exe oder WScript.exe führt zu folgendem Fehler: „Windows Script Host access is disabled on this machine. Contact your administrator for details.“ Bild 9.5: Protokollierung des Versuchs, trotz deaktiviertem WSH ein Script zu starten
9.1.4
WScript versus CScript
Der WSH ist genau genommen nicht nur ein Scripting Host, sondern umfasst zwei eng verwandte Scripting Hosts: WScript und CScript. Beide Scripting Hosts sind hinsichtlich ihres Befehlsumfangs fast gleich. Sie unterscheiden sich lediglich darin, wohin die Ausgaben gehen. Außerdem sind die Eingebauten Objekte von CScript ein klein wenig mächtiger als die von WScript.
241
9 Die Scripting Hosts
WScript.exe
WScript Bei WScript (implementiert in WScript.exe) erfolgt die Ausführung als Windows-Anwendung. Alle Ausgaben werden in Form von Dialogfenstern dargestellt. Wenn das Script viele Ausgaben macht, kann dies sehr lästig sein, da jedes Dialogfenster einzeln bestätigt werden muss. Zudem ist jedes Dialogfenster modal: Das Script hält an und wartet auf die Bestätigung. WScript eignet sich also für die unbeaufsichtigte Ausführung nur dann, wenn das Script keine Ausgaben macht. Gut geeignet ist WScript jedoch dann, wenn der Benutzer über jeden einzelnen Schritt informiert werden und dabei die jeweils erfolgten Veränderungen überprüfen möchte (also beispielsweise beim Debugging von Scripts).
Standard
WScript ist der Standard: Bei der Installation des WSH werden die WSH-Dateierweiterungen mit WScript verknüpft. Diese Verknüpfungen können in der Registrierungsdatenbank, in den Optionen des Windows Explorers oder mit der WSH-Kommandozeilenoption //H: geändert werden (siehe Tabelle 9.4). Unter Windows Vista funktioniert das Ändern des Standard-Scripting Host nur, wenn Sie tatsächlich mit Administratorrechten den Befehl ausführen, d.h. die Benutzerkontensteuerung (alias User Account Control (UAC) und User Account Protection (UAP)) zumindest temporär deaktiviert haben!
CScript.exe CScript Bei CScript (implementiert in CScript.exe) erfolgt die Ausführung des Script im
Kontext einer Kommandozeile (auch: Konsole oder DOS-Box). Die Form der Ausgabe hängt von den verwendeten Ausgabebefehlen ab: Alle Ausgaben über die Methode Echo() aus dem WSH-Eingebauten-Objekt WScript erfolgen in die DOS-Box. Alle Ausgaben über die spracheigenen Ausgabemethoden (z.B. MsgBox() in VBScript) werden weiterhin als modale Dialogfenster dargestellt. Ein Vorteil von CScript ist, dass es mit der Methode WScript.StdIn.Read Line() das Einlesen von Eingaben des Benutzers im DOS-Fenster unterstützt. Ausgaben können mit dem DOS-Befehl für Umleitungen (>) in eine Textdatei oder an einen Drucker umgeleitet werden. CScript hat außerdem den Vorteil, dass die Scriptausführung mit (STRG)+(C) jederzeit vom Benutzer abgebrochen werden kann. Bei WScript hilft – wenn modale Dialogfenster angezeigt werden – nur das Beenden der Anwendung mit dem Windows Task-Manager. Um CScript zum Standard für die Ausführung der Scripts zu machen, geben Sie nachfolgendes Kommando in der DOS-Box ein: C:\>cscript //H:cscript
Darauf antwortet der WSH mit: „CScript.exe“ ist jetzt Script Host-Standard. Logo
Normalerweise gibt CScript beim Scriptstart immer den Vorspann aus, der über den WSH informiert: Microsoft (R) Windows Script Host, Version 5.1 für Windows Copyright (C) Microsoft Corporation 1996-1999. Alle Rechte vorbehalten.
242
Windows Script Host (WSH)
Sie können diesen Vorspann mit der Kommandozeilenoption //Nologo ausschalten. Die Grundeinstellung für die Anzeige des „Logos“ lässt sich in der Registrierungsdatenbank ändern: HKEY_LOCAL_MACHINE\Software\Microsoft\Windows Script Host\Settings\ DisplayLogo. „1“ bedeutet, das Logo wird angezeigt, „0“ unterbindet die Anzeige.
Diesem Irrtum unterliegen viele: Ein Script wird nicht automatisch deshalb mit CScript gestartet, weil Sie es an der Kommandozeile starten. CScript muss entweder voreingestellt sein oder aber der Aufruf muss CScript.exe
lauten, sonst wird die Windows-Version gestartet.
Funktion
WScript.exe
CScript.exe
Anwendungstyp
Windows-Anwendung
DOS-Anwendung
Verhalten bei Start ohne Scriptname
Fenster zur Einstellung von Eigenschaften des WSH
Ausgabe eines HilfeTexts im DOS-Fenster
Ausgaben mit WScript.Echo() (Diese Methode wird in diesem Kapitel erklärt.)
Dialogfenster
DOS-Fenster
Länge der Ausgaben
begrenzt durch maximale Dialogfenstergröße (1023 Zeichen)
unbegrenzt
Ausgaben mit MsgBox() (Diese Methode wird in Kapitel 8 erklärt.)
Dialogfenster
Dialogfenster
Ausgaben mit
Nicht möglich
DOS-Fenster
Umleitung der Ausgaben von WScript.Echo() oder WScript.StdOut.WriteLine() an einen Drucker oder eine Textdatei (Diese Methode wird in diesem Kapitel erklärt.)
Nicht möglich
Möglich, z.B.
Eingaben mit
Nicht möglich
Tabelle 9.5: Zusammenfassung des Vergleichs zwischen WScript vs. CScript
WScript.StdOut.WriteLine()
(Diese Methode wird in diesem Kapitel erklärt.) cscript.exe >d:\ausgabe.txt
DOS-Fenster
WScript.StdIn.ReadLine()
(Diese Methode wird in diesem Kapitel erklärt.)
243
9 Die Scripting Hosts
Funktion
WScript.exe
CScript.exe
Versteckte Eingaben mit
Nicht möglich
DOS-Fenster
Dialogfenster
Dialogfenster
ScriptPW.GetPassword()
(Diese Methode wird in Kapitel 16.2 „Scripting-Password-Komponente“ erklärt.) Eingaben mit Inputbox() (Diese Methode wird in Kapitel 8 erklärt.) Kommandozeilenoptionen
Tabelle 9.6: Kommandozeilenoptionen für den WSH
244
WSH-Kommandozeilenoptionen Die folgende Tabelle zeigt alle Kommandozeilenoptionen, über die sowohl CScript als auch WScript verfügen. Bitte beachten Sie den doppelten Slash: Ein einfacher Schrägstrich wird dem Script als Argument übergeben. Durch den Doppelschrägstrich weiß der WSH, dass die Option für ihn gilt. Kommando- Bedeutung zeilenoption //B
Batchmodus: Alle Ausgaben von WScript.Echo() werden unterdrückt. Dies gilt nicht für Ausgaben, die von Sprachen direkt erzeugt werden (z.B. MsgBox() in VBS).
//I
Interaktiver Modus: Ausgaben werden dargestellt. (Dies ist die Standardeinstellung.)
//D
Debugging wird aktiviert: Bei einem Fehler wird der Debugger gestartet, sofern einer installiert und das Debugging durch die Registrierungsdatenbankeinstellungen grundsätzlich zugelassen ist (siehe dazu das Kapitel 19 „Fortgeschrittene Techniken“).
//X
Script wird im Debugger gestartet. Der Unterschied zur Option //D besteht darin, dass das Script in diesem Fall nicht auf einen Fehler wartet, sondern von der ersten Zeile an im Debugger startet.
//E:Engine
Unabhängig von der Dateierweiterung wird eine bestimmte Scripting Engine zur Ausführung der Scriptdatei verwendet.
//H:CScript
Einstellung der WSH-Variante, die verwendet wird, wenn ein Doppelklick oder Drag&Drop auf eine Datei erfolgt. Standard ist WScript. Diese Option verändert auf einfache Weise die Shell-Verknüpfung für zum WSH gehörende Dateierweiterungen auf CScript.
//H:WScript
Zurücksetzen der Standardstartoption auf WScript
//Job:jobname
Aus der angegebenen Scriptdatei wird nur ein bestimmter Job ausgeführt.
//T:nn
Timeout: Nach //T: kann angegeben werden, wie viele Sekunden das Script maximal laufen darf. Mit //T:2 wird das Script nach 2 Sekunden – sofern es nicht vorher regulär beendet wurde – mit der Meldung „Die Scriptausführungszeit wurde überschritten“ zwangsweise beendet.
Windows Script Host (WSH)
Kommando- Bedeutung zeilenoption //Logo
WSH-Version und der Copyright-Vermerk werden bei CScript angezeigt. (Dies ist die Standardeinstellung.)
//Nologo
Die Ausgabe der WSH-Version und des Copyright-Vermerks in der Kommandozeile wird bei CScript unterdrückt. Bei WScript hat diese Option keine Relevanz, da dort sowieso kein „Logo“ gezeigt wird.
//S
Speicherung der aktuellen Kommandozeileneinstellungen für diesen Benutzer
Wenn das Script eine Methode in einem COM-Objekt aufgerufen hat und währenddessen die mit //T gesetzte Zeitgrenze abläuft, wird das Script nicht sofort abgebrochen, sondern es erwartet die Rückkehr des Methodenaufrufs. Wenn ein COM-Methodenaufruf „hängt“, wird also ein Script trotz gesetzter Timeout-Zeit nicht ohne manuellen Eingriff enden.
9.1.5
Timeout bei Methodenaufrufen
Scriptdateien
Ein Script liegt beim WSH immer in einer Textdatei im Dateisystem vor. Dabei gibt es drei Verschiedene Formen Formen der Sprachidentifikation: 왘 Identifizierung der Scriptsprache über die Dateierweiterung 왘 Identifizierung der Scriptsprache über eine beim Start des Host angegebene Komman-
dozeilenoption (//E) 왘 XML-Datei mit Identifizierung der Scriptsprache innerhalb der Scriptdatei
Bild 9.6: WSH-Symbole
WSH-Dateien werden entsprechend ihrer Dateierweiterung durch unterschiedliche Symbole repräsentiert. Die Symbole von WScript.exe und CScript.exe sehen aus wie ein Bulletand-Stick-Diagramm (vgl. Kapitel 7): WScript.exe hat die IUnknown-Schnittstelle oben, CScript.exe unten.
245
9 Die Scripting Hosts
Einfache WSH-Scriptdateien Sprachiden- Eine einfache Scriptdatei kann nur genau ein Script in genau einer Scriptsprache beinhaltifizierung ten. Die Scriptsprache wurde durch die Dateierweiterung festgelegt, z. B.: per Dateierweiterung 왘 .vbs für Visual Basic Script 왘 .js für JScript 왘 .pls für PerlScript (sofern PerlScript installiert ist)
Sprachidenti- Wenn eine Datei eine andere Erweiterung hat, können Sie sie dennoch mit einem bestimmfizierung per ten Sprachinterpreter starten. Dazu müssen Sie die Scriptdatei explizit mit einer der beiden Kommandozeilenoption Umgebungen (WScript.exe oder CScript.exe) starten und hinter der Kommandozeile //E die
ProgID der gewünschten Active Scripting Engine angeben. WScript.exe "ich-bin-eine-Scriptdatei.txt" //E:VBScript
Sie finden dazu ein Beispiel auf der Buch-CD [CD:/code/hosts/WSH/Scriptdatei mit anderer Extension/], in dem eine Datei mit der Erweiterung .txt als VBS-Script gestartet wird. XML-strukturierte WSF-Dateien XML-strukturierte Scriptdateien
Ab WSH 2.0 sind die allgemeinen WSH-Scriptdateien mit der Erweiterung .wsf hinzugekommen (in der Beta-Version des WSH 2.0 trugen sie noch die aus zwei Buchstaben bestehende Erweiterung .ws). WSF-Dateien können mehrere Scripts in verschiedenen Sprachen enthalten und werden durch die Extensible Markup Language (XML) auf der Grundlage eines Satzes vordefinierter Elemente strukturiert. Eine WSF-Datei enthält genau ein Package. Jedes Package besteht aus einem oder mehreren Jobs. Jeder Job umfasst einen oder mehrere Scriptblöcke. Das nachfolgende Listing zeigt die Grundstruktur einer WSF-Datei. Listing 9.2: Grundstruktur XML-strukturierter WSH-Dateien im WSH 2.0
Jobs
246
Regeln Während die XML-Processing Instruction in der ersten Zeile und die Definition eines Package optional sind, ist der Aufbau aus mindestens einem Job- und einem Scriptblock zwingend. Im letzteren Fall ist dann das Root-Element. Ein Job kann beliebig viele Scriptblöcke enthalten, die in unterschiedlichen Active Scripting Engines implementiert wurden. Gemäß den XML-Konventionen muss jedes geöffnete Element auch wieder geschlossen werden. Eine Ausnahme bildet nur die XML-Processing Instruction.
Windows Script Host (WSH)
Alle Elementnamen müssen klein geschrieben werden. Eine Ausnahme ist die Processing Instruction, die wahlweise in Groß- oder Kleinbuchstaben geschrieben werden kann. Wenn andere Elemente nicht komplett klein geschrieben werden, dann werden diese Elemente einfach ignoriert. So kommt der Ausgabebefehl in dem folgenden Script nicht zur Ausführung, weil mit großem Anfangsbuchstaben geschrieben wurde. Der WSH liefert aber keine Fehlermeldung, weil die Bedingung erfüllt ist, dass Start- und Ende-Tag zueinander passen. msgbox "OK"
Durch das Weglassen der Processing Instruction wird der WSH in einen Modus versetzt, der weniger strenge Anforderungen an die Wohlgeformtheit von XML stellt. So würde nachfolgende WSF-Datei akzeptiert, obwohl die Groß-/Kleinschreibung nicht stimmt und die Anführungszeichen bei der Attribut-Wert-Zuweisung fehlen. msgbox "OK"
Mehrere Jobs Sofern von der Möglichkeit Gebrauch gemacht wird, durch die Definition eines Package mehrere Jobs in einer WSF-Datei zu vereinen, kann der Scriptbenutzer über die Kommandozeilenoption //job:jobname den auszuführenden Job auswählen. Fehlt die Angabe, wird der erste in der WSF-Datei enthaltene Job gestartet. XML-Element
Erläuterung
Dieser Ausdruck ist immer gleich, da derzeit nur XML 1.0 und keine externe Document Type Definition für XML-strukturierte WSH-Dateien unterstützt wird.
Diese Processing Instruction erlaubt die Deaktivierung des Debugging, indem Debug="False" gesetzt wird. Das Flag Error funktioniert nicht.
Definiert einen Job, optional kann eine JobID angegeben werden, die innerhalb einer Datei eindeutig sein muss.
Definiert einen Scriptblock. Wenn das Attribut src angegeben ist, wird die angegebene Datei eingebunden.
Tabelle 9.7: XML-Elemente mit ihren Attributen in WSFDateien
247
9 Die Scripting Hosts
XML-Element
Erläuterung
events="true|false"
Dieses Tag dient der Instanziierung statischer Objekte, die von allen Scriptblöcken nutzbar sind. Angegeben werden muss entweder eine ProgID oder eine CLSID.
Zur Einbindung von Typbibliotheken mit dem Vorteil, dass alle darin definierten Konstanten im Script verfügbar sind. Angegeben werden muss entweder die ProgID einer Klasse oder die LibID der Typbibliothek. Sofern mehrere Versionen der Typbibliothek installiert sind, kann durch version= die entsprechende Version spezifiziert werden.
wert Listing 9.3: Einsatz einer CDATA-Sektion in WSF-Dateien
Mehrsprachigkeit Ein XML-strukturiertes WSH-Script kann in mehreren Sprachen geschrieben sein. Für jeden -Block kann über das Attribut language eine Sprache definiert werden. Es kann beliebig viele -Blöcke innerhalb eines -Elements geben. Die einzelnen Scripts werden in der Reihenfolge ihres Vorkommens aufgerufen, d.h., alle Scripts eines Jobs werden beim Start des Jobs abgearbeitet (sofern es nicht zu einem Laufzeitfehler kommt).
248
Windows Script Host (WSH)
Echo("Hello World / PerlScript in WSF-Datei"); ]]> Listing 9.4: WSF-Datei mit Scripts in drei verschiedenen Sprachen
Es ist sogar möglich, eine Unterroutine in einem anderen Scriptblock aufzurufen, selbst wenn dieser Block eine andere Sprache verwendet. Wichtig ist aber, dass Sie nur Unterroutinen in vorgehenden Blöcken, nicht in nachfolgenden Blöcken aufrufen können. Dies ist ein Script von
[email protected] // ----- Unterroutine in JScript function jadd(a,b) { return(a+b) } msgbox "Berechnungsergebnis von JScript: "& jadd(1,2) msgbox "Ende?", vbYESNO Msgbox "Job2" Listing 9.5: Aufruf einer JScript-Routine von VBScript aus [Mehrsprachigkeit.wsf]
249
9 Die Scripting Hosts
Kommentare Sie können Kommentarzeilen nicht nur mit dem -Element, sondern auch – wie in XML üblich – mit dem speziellen -Element einfügen. Allerdings lässt sich dieses Element nicht innerhalb eines Scripts verwenden. Hier koennte ein groeßerer Kommentar stehen! ' Das Script startet... MsgBox "OK",,"Beispiel mit vielen Kommentaren" Listing 9.6: Verwendung von verschiedenen Kommentarmöglichkeiten [vieleKommentare.wsf]
Neuerung im WSH 5.6 Ab WSH 5.6 gibt es zahlreiche neue XML-Elemente. Alle diese nachstehend aufgeführten Elemente bis auf das Element dienen der Selbstbeschreibung eines Script, insbesondere der erwarteten Parameter. Tabelle 9.8: Neue XMLElemente im WSH 5.6
250
XML-Element
Unterele- Erläuterung ment von
Dieses Element gruppiert die verschiedenen Elemente, die der Selbstbeschreibung des Script dienen. Es hat selbst keinen Inhalt.
Beschreibung eines benannten Parameters, der in der Form /argumentname:wert übergeben wird
Beschreibung eines unbenannten Parameters. Unbenannte Parameter sind alle Parameter, die nicht mit einem Slash beginnen.
Windows Script Host (WSH)
XML-Element
Unterele- Erläuterung ment von
Beschreibung des Scripts
Beschreibungstext, in dem die Usage-Meldung vor der Liste der möglichen Parameter ausgegeben wird. In diesem Element enthaltene Leer- und Sonderzeichen werden bei der Ausgabe beachtet.
Anwendungsbeispiel
Beschreibungstext, in dem die Usage-Meldung nach der Liste der möglichen Parameter ausgegeben wird. Dies muss nicht zwingend ein Beispiel sein, sondern kann auch weiterer „normaler“ Beschreibungstext sein. In diesem Element enthaltene Leer- und Sonderzeichen werden bei der Ausgabe beachtet.
Benutzerdefinierter Hilfe-Text
Wenn dieses Element gefüllt ist, wird nur dieser Inhalt bei der Ausgabe der Usage-Nachricht verwendet. Die anderen Unter-Elemente von werden dann ignoriert. In diesem Element enthaltene Leer- und Sonderzeichen werden bei der Ausgabe beachtet.
XML-Element
WSH 1.0 (5.0)
WSH 2.0 (5.5)
x
x
WSH 5.6/5.7 x x
x
x
x
x x
x
x
x
x
x
x
x
x
Tabelle 9.9: Verfügbarkeit der XML-Elemente in den WSH-Versionen. Im WSH 1.0 gab es noch keine XMLElemente.
x
x x
WSH-Konfigurationsdateien Schon seit WSH 1.0 gibt es auch Dateien mit der Dateierweiterung .WSH. Dies sind Konfigurationsdateien für WSH-Scripts, ähnlich wie .pif-Dateien für DOS-Batch-Dateien. Man erzeugt eine .WSH-Datei, indem man im Explorer oder auf dem Desktop die Eigenschaften
Scriptbezogene Einstellungen in WSH-Dateien
251
9 Die Scripting Hosts
einer Scriptdatei (.wsf, .vbs, .js, .pls etc.) betrachtet. Sie sehen dann das in nachstehender Abbildung gezeigte Eigenschaftenfenster. Wenn Sie die Einstellungen für Timeout und Logo ändern, wird automatisch im selben Verzeichnis eine gleichnamige Datei mit der Erweiterung .wsh mit einer Verknüpfung zur Scriptdatei erzeugt. Diese Einstellungen sind äquivalent zu den WSH-Kommandozeilenoptionen //T, //LOGO und //NOLOGO. Zwar bestände die Möglichkeit, diese Einstellungen in Compound Files als erweiterte Dateiattribute abzulegen, davon macht der WSH aber keinen Gebrauch. [ScriptFile] Path=D:\CD\code\Hosts\WSH\WSH-datei\x.vbs [Options] Timeout=1 DisplayLogo=1 Listing 9.7: Inhalt einer WSH-Konfigurationsdatei
Sie finden Beispiele für WSH-Konfigurationsdateien auf der Buch-CD [CD:/code/hosts/ WSH/WSH-Konfigurationsdateien]. Bild 9.7: Eigenschaften eines WSHScript, die in einer Datei mit der Erweiterung .WSH gespeichert werden
Bitte beachten Sie, dass diese Einstellungen nur dann wirken, wenn Sie die .wsh-Datei starten. Wenn Sie die eigentliche Scriptdatei aufrufen, wird nicht nach einer .wsh-Datei im selben Verzeichnis gesucht! Globale Einstellungen
252
Wenn ein Doppelklick direkt auf WScript.exe ausgeführt wird, erscheint ein ähnlicher Konfigurationsdialog, der die Einstellungen global für alle Scripts ändert.
Windows Script Host (WSH)
9.1.6
Start eines Script
Scripts können wie eine normale Anwendung gestartet werden, also: 왘 an der Kommandozeile
Scripts starten
왘 durch Doppelklick auf die Scriptdatei bzw. auf Öffnen im Kontextmenü 왘 durch Drag&Drop beliebiger Dateien auf das Symbol einer Scriptdatei (seit WSH 2.0) 왘 über das Kontextmenü einer jeden Datei im Windows Explorer oder auf dem Desktop 왘 automatisiert durch den Zeitplandienst
An der Kommandozeile und im Zeitplandienst hat der Benutzer die explizite Wahl, ob Konfiguration CScript.exe oder WScript.exe gestartet wird. cscript scriptname.extension [option...] [arguments...] wscript scriptname.extension [option...] [arguments...]
Welche Variante durch einen Doppelklick oder Drag&Drop gestartet wird, bestimmt die Anwendungsverknüpfung der zum WSH gehörenden Dateierweiterungen. Diese sind in der Registrierungsdatenbank unter HKEY_CLASSES_ROOT definiert, können jedoch mit der //H-Kommandozeilenoption auf einfache Weise geändert werden (siehe Tabelle 9.6). Die Möglichkeit des Drag&Drop besteht erst seit WSH 2.0. Die Pfade der fallengelassenen Drag&Drop Datei werden dem Script in diesem Fall als Parameter übergeben. Auf der gleichen Grundlage funktionieren die Möglichkeiten, ein Script in das Kontextmenü einer Datei einzubauen. Sie haben einerseits die Möglichkeit, für einen bestimmten Dateityp einen neuen Kontextmenüeintrag zu registrieren. Dies können Sie über den entsprechenden Registrierungsdatenbankschlüssel für die Dateierweiterung unter HKEY_CLASSES_ROOT oder komfortabler über Extras/Ordneroptionen/Dateitypen im Windows Explorer ausführen. Die zweite Möglichkeit ist, das Script in den Senden An-Eintrag anzufügen. Dazu müssen Sie das Script (oder eine Verknüpfung zu dem Script) in das SendTo-Verzeichnis im Benutzerprofil des Benutzers legen. Diese Möglichkeit hat den Vorteil, dass das Script sofort für alle Dateitypen zur Verfügung steht. Der Nachteil ist, dass das Script für jeden Benutzer einzeln eingetragen werden muss, da es kein allgemeines Senden An-Menü gibt (anders als das Start-Menü, für das es auch eine benutzerunabhängige Definition in Form des All Users-Verzeichnisses gibt). Wenn Sie ein Script über ein Symbol mit einer Kommandozeilenoption starten wollen, dann müssen Sie eine Verknüpfung zu der Datei erstellen und dort die Kommandozeilenoption eintragen. Prüfung auf die WSH-Variante Welche Variante des WSH das Script ausführt, ist WScript oder eine wichtige Frage, da einige Funktionen (insbesondere der Zugriff auf die Standardein- CScript? und -ausgabe) nur in CScript zur Verfügung stehen. Leider gibt es kein Attribut, das direkt zwischen den beiden Varianten unterscheidet. Das Attribut FullName enthält aber den kompletten Pfad zum aktuellen Host. Durch Extraktion der letzten elf Zeichen der Zeichenkette kann geprüft werden, ob CScript.exe oder WScript.exe ausgeführt wird. if UCASE(right(wscript.fullname,11)) = "CSCRIPT.EXE" then variante = "CScript" else variante = "WScript"
253
9 Die Scripting Hosts
end if if variante = "CScript" then Msgbox "Dieses Skript läuft mit der Kommandozeilenversion des WSH!" else Msgbox "Dieses Skript läuft mit der Windows-Version des WSH!" end if Listing 9.8: Ein nützlicher Codeblock, der in vielen Scripts Verwendung findet, um zu prüfen, ob das Script mit der richtigen Variante des WSH gestartet wurde. [wsh_variante_pruefen.vbs]
Start mit Script erzwingen Auf Basis des vorherigen Script und unter Vorgriff auf ein Objekt (WSHShell), das erst in Kapitel 10 behandelt wird, kann man auch erzwingen, dass ein Script mit einer bestimmten der beiden WSH-Varianten gestartet wird. If UCASE(right(wscript.fullname,11)) = "WSCRIPT.EXE" Then set WSHShell = CreateObject("WSCript.Shell") Dim Befehl Befehl = "cscript.exe " & chr(34) & wscript.scriptfullname & chr(34) Msgbox "Start mit WSCRIPT.EXE nicht erlaubt. Skript startet daher nun mit CSCRIPT.EXE!" WSHShell.Run Befehl else wscript.stdout.Writeline "Bitte ENTER drücken" wscript.stdin.readline end if Listing 9.9: Erzwingen des Starts mit CSCRIPT [CScript_erzwingen.vbs] Remote Entfernte Scriptausführung Neu seit dem WSH 5.6 ist die Möglichkeit, ein Script auf Scripting einen entfernten Rechner hochzuladen und dort zu starten. Diese Möglichkeit wird im
Kapitel 19 „Fortgeschrittene Techniken“ beschrieben.
9.1.7
Befehlszeilenparameter für Scripts
Parameter
Administrative Scripts benötigen oft Eingabedaten, die via Kommandozeilenparameter übergeben werden. WSH 1.0 und 2.0 besitzen zwar über die Arguments-Objektmenge die Möglichkeit, auf die übergebenen Parameter zuzugreifen, die Prüfung und Auswertung der Parameter ist jedoch dem Scriptentwickler überlassen. Dabei ist gerade die Entwicklung der zugehörigen Prüfroutinen eine zeitraubende Aufgabe.
Neue Möglichkeiten ab WSH 5.6
Ab WSH 5.6 hat Microsoft die Möglichkeit eingebaut, in .wsf-Dateien per XML die erwarteten Parameter zu definieren, so dass die Scripts selbst beschreibend werden. Dabei können zu jedem Parameter folgende Angaben gemacht werden: 왘 Argumenttyp (benannt oder unbenannt) 왘 Name 왘 Datentyp (String, Boolean oder Simple) 왘 ob ein Parameter erforderlich oder optional ist
254
Windows Script Host (WSH)
왘 ob ein Parameter gleichen Namens mehrfach vorkommen darf (nur für Parameter des
Typs „unbenannt“) 왘 wie viele Parameter gleichen Namens benötigt werden (nur für Parameter des Typs
„unbenannt“) Auf Basis dieser Informationen leistet der WSH zwei Dienste: 왘 Prüfung beim Start des Script, ob diese Bedingungen erfüllt sind
Prüfung und Usage-Informationen
왘 Zusammenstellung einer Hilfeinformation („Usage“), die dem Aufrufer mitteilt, welche
Parameter erwartet werden Hinweis: Die automatische Prüfung der Parameter war zwar zwischenzeitlich im Gespräch, Einschränkung ist jedoch im WSH 5.6/5.7 nicht realisiert. Benannte versus unbenannte Argumente Der WSH unterstützt sowohl benannte als auch unbenannte Argumente: 왘 Ein benanntes Argument beginnt mit einem Slash („/“) und hat die allgemeine Form
Benannte
/Argumentname:Wert. Der WSH trennt beim Aufruf Argumentname und Wert, so dass Argumente
der Zugriff für den Entwickler einfacher ist. Der Zugriff im Script erfolgt über die Objektmenge WScript.Arguments.Named. Argumente, die Leerzeichen enthalten, müssen in Anführungszeichen stehen. Bei benannten Parametern ist sowohl die Form "/Argumentname:Wert" als auch /Argumentname: "Wert" erlaubt. Es gibt folgende Sonderfälle: /Argumentname:
übergibt eine Leerzeichenkette („“). /Argumentname
übergibt keinen Wert (isempty() liefert True). /Argumentname+
übergibt den Boolean-Wert True. /Argumentname-
übergibt den Boolean-Wert False. 왘 Ein unbenanntes Argument ist jedes Argument, das nicht mit einem Slash beginnt. Der
Unbenannte
WSH lässt diese Argumente unberührt. Der Zugriff im Script erfolgt über die Objekt- Argumente menge WScript.Arguments.Unnamed.
Zugriff auf die Argumente innerhalb des Script Die aus WSH 1.0/2.0 bekannte Objektmenge WScript.Arguments enthält weiterhin alle Argumente in unberührter Form. WScript.Arguments wird in WScript.Arguments.Unnamed und WScript.Arguments.Unnamed in zwei disjunkte Teile aufgespaltet.
255
9 Die Scripting Hosts
Usage
Usage-Informationen Die Usage-Informationen werden in drei Fällen angezeigt: 왘 Der Aufrufer startet das Script mit der Option /?. 왘 Die Prüfung der Parameter war nicht erfolgreich. 왘 Das Script ruft selbst die Funktion WScript.Arguments.ShowUsage() auf.
Wenn in der XML-Datei das Element definiert ist, zeigt ShowUsage() dessen Inhalt. Sonst stellt der WSH den Hilfetext aus dem Inhalt der Elemente , , und zusammen. Beispiel
Beispiele Das folgende Script enthält eine Selbstbeschreibung. Es erwartet 1 bis n Pfade zu Eingabedateien, einen Pfad zu einer Ausgabedatei und – optional – den Schalter /ueberschreiben. (C)
[email protected] Dieses Skript kopiert den Inhalt von mehreren Textdateien in eine neue Textdatei zusammen! Autor: Holger Schwichtenberg für das Buch "Windows- und BackOffice-Scripting" siehe http://www.windows-scripting.de ------------------------------------------- -------------------------------------------Anwendungsbeispiel: merge_files.wsf c:\buch\WSH\datei1.txt c:\buch\WSH\datei2.txt e:\buch\WSH\datei 3.txt /Ziel:c:\buch\WSH\datei_ausgabe.txt /ueberschreiben ... Listing 9.10: merge_file.wsf
Der Aufruf mit merge_files.wsf /?
führt zu nachstehendem Dialogfenster. Die optionalen Parameter werden wie üblich durch eckige Klammern angedeutet. Bild 9.8: Usage-Informationen von merge_ files.wsf
Wenn ein -Tag vorhanden ist, wird der Inhalt dieses Elements ausgegeben. Die Selbstbeschreibung der Attribute wird dann ignoriert. Dies ist die benutzerdefinierte Usage-Information! wscript.arguments.showusage Listing 9.11: Einsatz des -Elements [benutzerdefinierte_usage.wsf] Bild 9.9: Ausgabe von benutzerdefinie rte_usage .wsf
9.1.8 Include()
Einbinden von anderen Scriptdateien
Der WSH 2.0 bietet für .wsf-Dateien einen eleganten Weg der Einbindung anderer Scriptdateien. Allerdings können auf diesem Wege nur nicht-XML-strukturierte WSH-Dateien (.vbs, .js etc.) eingebunden werden. Man kann eine .wsf-Datei nicht in eine andere .wsf-Datei einbinden.
Im folgenden Beispiel wird eine JScript-Scriptdatei eingebunden, die im selben Verzeichnis wie das einbindende Script liegt. Das Vorgehen über das -Tag entspricht dem Vorgehen in DHTML (siehe Kapitel zum Internet Explorer Scripting). Skript von
[email protected] msgbox "1 + 2 = " & jadd(1,2) Listing 9.12: main.wsf bindet die Datei inc.js ein.
// ----- Unterroutine in JScript function jadd(a,b) { return(a+b) } Listing 9.13: Einzubindende Datei [inc.js]
258
Windows Script Host (WSH)
In nicht-XML-strukturierte .vbs-Scripts können Sie andere Scripts mit Hilfe der in Kapitel 8 vorgestellten Routine Include() einbinden, sofern Sie VBS 5.0 oder höher verwenden.
9.1.9
Statische Objekte und Einbinden von Typbibliotheken
Im Rahmen von .wsf-Dateien (also erst seit Version 2.0) unterstützt der WSH auch statische Objekte sowie die Einbindung von Typbibliotheken. Statische Objekte Statische Objekte werden beim Start des Script durch den Scripting Host instanziiert. Jedem statischen Objekt wird ein Name zugewiesen. Über diesen Namen Element steht die Instanz allen Scripts eines Jobs zur Verfügung, so als wären sie Eingebaute Objekte des Host. Ebenso wie bei Eingebauten Objekten kann die Zuordnung durch ein Script nicht geändert werden. Statische Objekte werden mit dem -Element erzeugt.
Das Element benötigt ein Attribut ID, das den Namen der Objektvariablen angibt, unter dem das instanziierte Objekt zur Verfügung stehen soll. Als zweites Attribut muss entweder die ProgID oder die CLSID der zu instanziierenden Klasse angegeben sein. Optional ist das dritte Attribut Events. Wenn dieses auf True gesetzt wird, achtet der WSH Ereignisse auf Ereignisse, die das Objekt erzeugt. Die Ereignisse können dann mit einer Unterroutine abgefangen werden, deren Name so aufgebaut ist: ID_Ereignisname
Eine andere Alternative der Ereignisbindung bietet die Methode WScript.CreateObject(). Mehr dazu erfahren Sie im folgenden Kapitel. Typbibliotheken Die Einbindung von Typbibliotheken (allgemeine Erläuterungen zum Element sant, weil damit die in einer Typbibliothek definierten symbolischen Konstanten im Script zur Verfügung stehen. Anders als bei VB 6.0/VBA ermöglichen die Typbibliotheken jedoch nicht das frühe Binden; das ist in Scripts grundsätzlich unmöglich.
Angegeben werden muss entweder die ProgID einer Klasse oder die TypeLibID der Typbibliothek. Sofern mehrere Versionen der Typbibliothek installiert sind, kann durch version= die entsprechende Version spezifiziert werden. Beispiel Das folgende .wsf-Script zeigt die Verwendung beider Möglichkeiten. Das Beispiel -Element erzeugt eine statische Instanz der Klasse Scripting.FileSystemObject, so dass das Objekt unter FSO dem Script zur Verfügung steht. Außerdem bindet die passende Typbibliothek mit ein, so dass in der Methode OpenTextFile() die symbolischen Konstanten ForAppending und TristateUseDefault verwendet werden können. Mehr über diese Klasse erfahren Sie in Kapitel 10.2.
259
9 Die Scripting Hosts
Dim tx ' As Scripting.TextStream Set tx = FSO.OpenTextFile("d:\buch\docs\test2.txt", _ ForAppending, True, TristateUseDefault) tx.WriteLine "Nur ein Test" tx.Close WScript.Echo "Gespeichert!" Listing 9.14: Statische Objekte und Typbibliotheken in WSF-Dateien [typelib_verwendung.wsf]
9.1.10 Eingebaute Objekte im WSH
Die eingebauten Objekte des WSH
Der WSH besitzt einige Eingebaute Objekte, die von dem Stammobjekt WScript ausgehen. Das WScript-Objekt und seine Unterobjekte stellen folgende Funktionen bereit: 왘 Anzeige von Dialogfenstern und Ausgabe in das DOS-Fenster
Bild 9.10: Objektmodell der Eingebauten Objekte im WSH 1.0
WScript [IntrinsicObject]
Arguments
WSHCollection
String
왘 Informationen über das Script und den Scripting Host 왘 Anhalten des Script für eine bestimmte Zeit
Bild 9.11: Objektmodell der Eingebauten Objekte im WSH 2.0
WScript [IntrinsicObject]
StdIn StdOut StdErr Arguments
Scripting.TextStream
WSHCollection
String
260
Windows Script Host (WSH)
왘 Zugriff auf die übergebenen Parameter (Arguments-Objektmenge). Die untergeord-
neten Objektmengen NamedArguments und UnnamedArguments sind erst ab WSH 5.6 verfügbar. 왘 Zugriff auf Standardeingabe und Standardausgabe (StdIn, StdOut, StdErr) 왘 Zugriff auf Instanzen von COM-Klassen Die Typbibliothek für die Eingebauten Objekte des WSH steckt in der wscript.exe-Datei Typbibliothek („Library IHost“). Dies bedeutet aber nicht, dass die eingebauten Objekte auch aus anderen Anwendungen nutzbar wären. Die Typbibliothek dient lediglich dazu, Eingabehilfen in geeigneten Entwicklungsumgebungen bereitzustellen. Bild 9.12: Objektmodell der Eingebauten Objekte im WSH 5.6/5.7
WScript [IntrinsicObject]
StdIn StdOut StdErr Arguments
Scripting.TextStream
WSHCollection
String
NamedArguments
WSHCollection
String
UnNamedArguments
WSHCollection
String
Basisfunktionen im WScript-Objekt WScript ist keine instanziierbare COM-Klasse: Es kann daher innerhalb des WSH immer Objektmodell nur genau ein WScript-Objekt geben und die Klasse kann nicht außerhalb des WSH genutzt werden. WScript muss nicht instanziiert werden, sondern ist automatisch verfügbar.
Ausgaben mit Echo() Die Methode Echo() ist der zentrale Ausgabebefehl des WSH.
Echo()
WScript.Echo Arg1, Arg2, Arg3, ... Echo() erlaubt die Angabe mehrerer Zeichenketten oder Zeichenkettenvariablen, die nacheinander ausgegeben werden. Als Trennzeichen zwischen den Argumenten wird ein Leerzeichen eingefügt. Statt der Abtrennung der einzelnen Teile der Ausgabe in verschiedene Parameter wäre in Visual Basic auch eine Verknüpfung mit dem „&“-Operator möglich. Dann sind jedoch gewünschte Leerzeichen selbst zu setzen. Beide Möglichkeiten demonstriert das folgende Beispiel.
261
9 Die Scripting Hosts
WScript.Echo "Heute ist der", date(), "!" WScript.Echo "Heute ist der " & date() & " !" Listing 9.15: Zwei äquivalente Verwendungen der Methode Echo() [echo_demo.vbs] Bild 9.13: Ausgabe von Echo_Demo.vbs: Dieses Dialogfenster erscheint so zweimal. Titelzeile
Der Text in der Titelzeile des Dialogfensters kann bei Echo() nicht beeinflusst werden. Er ist immer „Windows Script Host“ (im WSH 2.0, 5.6 und 5.7) bzw. „Windows Scripting Host“ im WSH 1.0. Das Verhalten von Echo() unterscheidet sich bei WScript und CScript:
Echo() in WScript
왘 WScript öffnet ein Dialogfenster (ähnlich wie der Befehl MsgBox() in Visual Basic). Im
Echo() in CScript
왘 CScript schreibt die übergebenen Texte in die Standardausgabe. Diese ist üblicherweise
Gegensatz zu MsgBox() erlaubt Echo() keine weitere Spezifikation der Gestaltung des Fensters. Der Titel ist immer „Windows Script Host“ bzw. „Windows Scripting Host“ (s. o.), einzige Schaltfläche ist immer die ok-Schaltfläche. Dementsprechend gibt Echo() auch keinen Wert zurück, der Auskunft darüber liefert, welche Schaltfläche gedrückt wurde. das DOS-Fenster, in dem das Script gestartet wurde. Die Standardausgabe kann jedoch mit dem „>“-Befehl umgeleitet werden. CScript sendet am Ende jedes Echo()-Befehls ein CR/LF (carriage return/line feed). Damit wird erreicht, dass jede Echo()-Ausgabe in einer neuen Zeile beginnt. Wie bei anderen DOS-Befehlen auch ist es bei CScript möglich, die Ausgabe an einen Drucker oder in eine Datei umzuleiten. cscript d:\buch\WSH\script1.vbs >prt cscript d:\buch\WSH\script2.vbs >d:\buch\WSH\log.txt
Die Ausgaben von Script1 werden direkt auf dem Drucker ausgegeben. Die Ausgaben von Script2 werden in eine Textdatei geschrieben. In beiden Fällen gibt es keine Bildschirmausgabe! Mehr Optionen als die Echo()-Methode bietet die Methode in der Klasse WSHShell.Popup() aus der WSH Runtime Library. WScript öffnet bei jedem Echo()-Befehl ein neues Fenster. Das kann sehr lästig werden. Mit dem manuellen Einfügen eines chr(13) (alias vbCR; vbCR ist eine in allen VB-Dialekten vordefinierte Konstante) können Zeilenumbrüche bei WScript erzeugt werden, so dass mehrere Ausgaben übersichtlich in ein Fenster passen. s = "Guten Tag!" & chr(13) s = s & "Heute ist der " & date() & "!" & chr(13) s = s & "Das Skript startet nach dem Klicken von OK..." WScript.Echo s
262
Windows Script Host (WSH)
Say() Die Kapselungsfunktion say() ist im WSH über WScript.Echo() definiert.
Say() im WSH
Sub say(s) WScript.Echo s End Sub
ShowUsage() Die Methode ShowUsage() blendet ein Fenster ein, das Informationen über ein Script zeigt. Wenn in der XML-Datei das Element definiert ist, zeigt ShowUsage() den Inhalt dieses Elements. Bild 9.14: Ausgabe von ShowUsage()
Die Methode ShowUsage() funktioniert auch bei nicht-XML-strukturierten WSHDateien, jedoch gibt das Dialogfenster dann keine Parameter, sondern nur den Namen des Scripts selbst aus, da die Definition der erwarteten Parameter nur in WSF-Dateien möglich ist.
Einschränkung
Informationen über den WSH und das Script Die Klasse WScript bietet sechs Attri- Informationen über die bute mit Informationen über den Scripting Host und das laufende Script. Umgebung
Attributname Erläuterung Name
Name liefert den Namen des Scripting Host zurück, also trivialerweise „Windows Script Host“, auch wenn das Script mit CScript gestartet wurde. Unter WSH 1.0 erhalten Sie die Zeichenkette „Windows Scripting Host“.
FullName
FullName liefert den vollständigen Pfad zu dem Scripting Host, in dem das aktuelle Script ausgeführt wird. Damit kann unterschieden werden, ob das Script mit WScript oder CScript gestartet wurde.
Path
Path liefert den Pfad zu dem Scripting Host, unter dem das Script ausgeführt wird. Es enthält die gleichen Informationen wie FullName,
Tabelle 9.10: Attribute der Klasse WScript
jedoch ohne den Namen der Programmdatei. ScriptFullName
ScriptFullName liefert den vollständigen Pfad (inklusive Dateinamen) des Script, das gerade ausgeführt wird.
ScriptName
Im Gegensatz zu ScriptFullName liefert dieses Attribut nur den Namen der Scriptdatei.
Version
Dieses Attribut liefert die Version des Scripting Host, in dem das aktuelle Script ausgeführt wird.
263
9 Die Scripting Hosts
WScript.Echo "Dieses Skript läuft in folgendem Scripting Host: ", WScript.Name WScript.Echo "Hier liegt der Scripting Host: ", WScript.Path WScript.Echo "Hier liegt der Scripting Host (inkl. Dateiname):" _ WScript.FullName WScript.Echo "Version des Scripting Hosts: " & WScript.Version WScript.Echo "Hier liegt das Skript: " & WScript.ScriptFullName WScript.Echo "Dateiname des Skripts: " & WScript.ScriptName Listing 9.16: Informationen über den Scripting Host und das Script [WSH_Info.vbs] Wichtige Hilfsroutinen
Viele Scripts benötigen Eingabedateien, die man sinnvollerweise in das gleiche Verzeichnis legt wie das Script selbst. Um dann auf diese Dateien zuzugreifen braucht man aber oft den absoluten Pfad dahin. Leider hilft das WScript-Pbjekt hier nicht direkt, sondern man muss mit Hilfe der FileSystemScripts (die später in diesem Buch noch ausführlich besprochen werden) den Ordnerpfad aus dem Standort des Script extrahieren. Die beiden folgenden Hilfsroutinen sind in der Praxis wichtige Elemente vieler Scripts . ' === Ermitteln des Ordners, in dem das Skript liegt Function GetScriptFolder() Dim objFSO Set objFSO = CreateObject("Scripting.FileSystemObject") GetScriptFolder = objFSO.GetFile(wscript.ScriptFullName).ParentFolder End Function ' === Absoluter Pfad zu einer Datei, die im gleichen Verzeichnis wie das Skript liegt Function GetFullPathForLocalFile(filename) GetFullPathForLocalFile = GetScriptFolder() & "/" & filename End Function Listing 9.17: Hilfsroutinen zur Ermittlung des Pfades, in dem sich das Script derzeit befindet [WS_SriptLib.vbs]
StdIn, StdOut Neu seit WSH 2.0 ist, dass das eingebaute Objekt WScript nun drei Unterobjekte besitzt: und StdErr StdIn, StdOut und StdErr bieten Zugriff auf die Standardeingabe- und -ausgabegeräte.
WScript bedient sich hier der Komponente Scripting Runtime. StdIn, StdOut und StdErr sind jeweils Instanzen der Klasse Scripting.Textstream.
Diese Unterobjekte funktionieren aber nur, wenn das Script durch CScript, also durch die Kommandozeilenversion des WSH, aufgerufen wurde. Beim Start mit WScript erscheint der Fehler 80070006: „Die Zugriffsnummer ist nicht definiert“. Ab Windows XP lautet der Fehlertext: „Das Handle ist ungültig“. WScript.StdOut.WriteLine "Wie heissen Sie?" name = WScript.StdIn.Readline WScript.StdOut.WriteLine "Hallo " & name & "!" WScript.StdErr.WriteLine "Kein Fehler!" Listing 9.18: Beispiel zur Verwendung von StdIn, StdOut und StdErr in der DOS-Eingabeaufforderung [WSH_StandardEinAusgabe.vbs]
264
Windows Script Host (WSH)
Mit dieser Funktion lassen sich WSH-Scripts nun auch in Umgebungen einsetzen, die nur über die Standard-I/O-Geräte kommunizieren können, beispielsweise als Common Gateway Interface (CGI)-Scripts für Webserver. Das Script mit Sleep() schlafen schicken Seit Version 2.0 unterstützt der WSH die Sleep() Methode Sleep(ms) im Eingebauten Objekt WScript, die ein Script für eine bestimmte Anzahl von Millisekunden anhält. Dies ist beispielsweise sinnvoll in Zusammenhang mit der SendKeys()-Funktion in der Klasse WSHShell aus der WSH Runtime-Komponente (vgl. Kapitel 10.1). wscript.echo "Skript startet..." wscript.sleep(3000) wscript.echo "3 Sekunden sind vergangen..." Listing 9.19: Beispiel für Sleep()
Ein weiteres wichtiges Anwendungsgebiet von Sleep() ist die ereignisgesteuerte Programmierung im WSH (siehe Abschnitt „Ereignisbehandlung“). Scriptende Die Quit()-Methode beendet die Ausführung des Script: WScript.Quit Quit() [ErrorCode]. Als optionaler Parameter kann eine Fehlernummer als Zahl angegeben werden. Im Standardfall wird 0 zurückgegeben. Der Befehl end aus VB 6.0/VBA steht in VBS nicht zur Verfügung und kann daher nicht zum Beenden eines WSH-Script verwendet werden. Zugriff auf die Befehlszeilenparameter Im WSH 1.0 und 2.0 gab es nur eine einfache Objektmenge WScript.Arguments, die alle ArgumentsBefehlszeilenparameter enthält. Ab WSH 5.6 sind die Parameter zusätzlich in die Objekt- Objektmenge mengen WScript.Arguments.Named und WScript.Arguments.Unnamed aufgespaltet. Die einfache Arguments-Objektmenge Das Attribut Arguments enthält einen Zeiger auf eine Objektmenge vom Typ WSHCollection, die automatisch beim Start eines Script angelegt und mit den Kommandozeilenparametern gefüllt wird. Die Objektmenge kann nur gelesen werden; es gibt keine Möglichkeit, eine eigene Instanz von WSHArguments anzulegen. Die Objektmenge enthält Zeichenketten, keine Unterobjekte (diese Ausnahme wird in Kapitel 10.1 in Zusammenhang mit den Objektmengen der WSH Runtime Library ausführlich erläutert). Die WSHArguments-Objektmenge bietet die üblichen Member Count und Item an. Das zusätzliche Attribut Length hat die gleiche Funktion wie Count. Das nachfolgende Beispiel listet alle übergebenen Parameter auf. Set Args = WScript.Arguments ' Iteration über alle Argumente For i = 0 to Args.Count – 1 WScript.Echo Args(i) Next Listing 9.20: Liste der Parameter des WSH-Script [zieh_etwas_auf_mich.vbs]
Üblicherweise ist die Reihenfolge von Parametern bei Kommandozeilenbefehlen nicht rele- inargs() vant. Eine Prüfung auf das Bestehen von Schaltern in WSHArguments sollte daher unabhängig vom Index innerhalb der Objektmenge erfolgen. Die VBS-Funktion inargs() löst dies auf elegante Weise.
265
9 Die Scripting Hosts
function inargs(s) dim a inargs = False for a = 1 to wscript.arguments.Count If UCase(wscript.arguments(a-1)) = _ UCase(s) Then inargs = True next end function Listing 9.21: inargs() prüft auf die Existenz eines bestimmten Schalters.
Das Hauptprogramm des Script kann diese Funktion nun aufrufen und erfragen, ob ein Schalter in den Kommandozeilenparametern vorkommt. If inargs("/h") Then ' Drucke Hilfetext ... End If Listing 9.22: Beispiel für den Einsatz von inargs()
Wenn das Script dadurch gestartet wurde, dass eine oder mehrere Dateien per Drag&Drop auf das Symbol des Script gezogen wurden, so enthält die Arguments-Objektmenge die Pfade zu diesen Dateien, so dass das Script mit diesen Dateien arbeiten kann. Gleiches gilt, wenn Sie das Script über das Senden An-Menü aufrufen. Zwei Einzel- Die NamedArguments- und die UnnamedArguments-Objektmenge Die Namedlisten Arguments-Objektmenge enthält die Menge der benannten Parameter, während die Unnamed-
Arguments-Objektmenge die unbenannten Parameter umfasst. Beide Objektmengen sind Unterobjekte der WScript.Arguments-Objektmenge.
Die Objektmengen haben folgende Mitglieder: 왘 Item(Index) liefert ein bestimmtes Argument. Dabei ist zu beachten, dass in der Unnamed-
Arguments-Objektmenge Item() als Index eine Zahl zwischen 0 und n erwartet, während die NamedArguments-Objektmenge als Index eine Zeichenkette mit dem Namen des
gewünschten Befehlszeilenparameters erwartet. 왘 Count liefert die Anzahl der Befehlszeilenparameter in der Objektmenge. 왘 Zusätzlich stellt die NamedArguments-Objektmenge die Methode Exists(Name) bereit, mit der geprüft werden kann, ob ein bestimmter benannter Parameter übergeben wurde. Beispiel
Beispiel Das bereits zuvor verwendete Beispiel wird nun um Routinen erweitert, die alle drei Objektmengen ausgeben. (C)
[email protected]
266
Windows Script Host (WSH)
Dieses Skript kopiert den Inhalt von mehreren Textdateien in eine neue Textdate i zusammen! Autor: Holger Schwichtenberg für das Buch "Windows- und BackOffice-Scripting" siehe http://www.windows-scripting.de ------------------------------------------- -------------------------------------------Anwendungsbeispiel: merge_files.wsf c:\buch\WSH\datei1.txt c:\buch\WSH\datei2.txt e:\buch\WSH\datei 3.txt /Ziel:c:\buch\WSH\datei_ausgabe.txt /ueberschreiben Set WSHArguments = WScript.Arguments WScript.Echo WScript.Echo WScript.Echo For I = 0 to
"--------------------" "Alle Parameter:" "--------------------" WSHArguments.Count – 1
267
9 Die Scripting Hosts
WScript.Echo WSHArguments (I) Next WScript.Echo "--------------------" WScript.Echo "Unbenannte Parameter:" WScript.Echo "--------------------" Set UnnamedArguments = WScript.Arguments.Unnamed For I = 0 to UnnamedArguments.Count – 1 WScript.Echo UnnamedArguments (I) Next WScript.Echo "--------------------" WScript.Echo "Benannte Parameter:" WScript.Echo "--------------------" Set NamedArguments = WScript.Arguments.Named For each n in NamedArguments if isempty(NamedArguments.item(n)) then WScript.Echo n & " hat keinen Wert" else WScript.Echo n & " = " & NamedArguments (n) end if Next Listing 9.23: Unterscheidung der verschiedenen Argumenttypen im WSH 5.6/5.7 [merge_files.wsf]
Zugriff auf externe COM-Komponenten Create- Das Eingebaute Objekt WScript verfügt über eine eigene Methode zur Instanziierung von Object() automatisierungsfähigen COM-Klassen. Diese Methode bietet gegenüber den Standard-
funktionen der jeweiligen Scriptsprachen (CreateObject() in VBScript, CreateActiveXObject() in JScript etc.) den Vorteil, dass eine Bindung an Ereignisbehandlungsroutinen möglich ist. Der WSH kann sich also im Gegensatz zu vielen anderen Scripting Hosts, die nur Ereignisse von Eingebauten Objekten verarbeiten können, auf Ereignisse beliebiger COM-Klassen registrieren. WScript.CreateObject(ProgID, [Prefix])
Ein häufiger Fehler ist die Verwechslung der VB-Funktion CreateObject() mit der Methode CreateObject() aus dem WScript-Objekt. Beide Funktionen haben einen zweiten, optionalen Parameter. Bei der VB-Funktion erlaubt dieser Parameter jedoch die Angabe eines entfernten Rechners, auf dem die Instanziierung ausgeführt werden soll. Bei WScript.CreateObject() wird der zweite Parameter für die Ereignisbindung verwendet. Wenn Sie die beiden CreateObject() miteinander verwechseln, werden Sie unerwartete Ergebnisse erhalten. Ereignisse
268
Ereignisbehandlung im WSH Neben der ProgID kann optional ein frei wählbarer Bezeichner angegeben werden, der Präfix genannt wird, weil er den entsprechenden Ereignisbehandlungsroutinen vorangestellt werden muss. Sofern das Objekt ein Ereignis auslöst, wird nach einer Ereignisroutine gesucht, die aus dem Präfix gefolgt vom Namen des ausgelösten Ereignisses besteht. Es ist üblich, aber nicht zwingend, das Präfix wie die Objektvariable zu
Windows Script Host (WSH)
nennen und auf einen Unterstrich „_“ enden zu lassen, so dass eine typische VB-Ereignisbehandlungsroutine der Form „Objekt_Ereignis“ entsteht. Natürlich ist man durch die Angabe des Präfix-Parameters nicht verpflichtet, zu allen Ereignissen, die das Objekt auslösen könnte, eine Ereignisbehandlung zu definieren. Die Ereignisbindung kann in .wsf-Dateien auch über das -Tag stattfinden. Wenn das Attribut Events auf True gesetzt wird, dann dient das ID-Attribut als Präfix für die Ereignisbehandlungsroutinen. Allerdings funktioniert die Ereignisverarbeitung im WSH nur so lange, wie das Script noch Warten auf läuft. Wenn also ein Vorgang gestartet wird, der asynchrone Ereignisse liefert (also die Kon- Ereignisse trolle an das Script zurückgibt), muss in der Zwischenzeit das Script beschäftigt werden. Jedoch darf das Script auch nicht zu sehr beschäftigt sein, denn solange noch Befehle ausgeführt werden, können keine Ereignisbehandlungsroutinen abgearbeitet werden; der WSH kann Scriptbefehle nicht parallel ausführen. Das Script mit einer Zählschleife am Laufen zu halten, ist also kein Ausweg, weil dies der WSH-Ereignisbehandlung keine Zeit einräumt. Die Ereignisbehandlung kann nur in zwei Fällen Ereignisbehandlungsroutinen abarbeiten: Entweder zeigt das Script ein Dialogfenster an (Msgbox(), Inputbox(), WScript.Echo() etc.) oder es wartet mit WScript.Sleep(). Dabei ist die Anzeige eines Dialogfensters meist kein guter Ausweg und es besteht die Warten mit Gefahr, dass das Dialogfenster weggeklickt und damit das Script entweder beendet wird Dialogfenstern oder wieder beschäftigt ist. Andererseits kann das Script auch nach Abarbeitung aller Ereignisse erst enden, wenn das Dialogfenster geschlossen wird. Bei der Verwendung von Sleep() vermeiden Sie die lästige Anzeige eines Dialogfensters. Warten mit Der Nachteil von Sleep() scheint zu sein, dass man damit das Script nur eine bestimmte Sleep() Zeit ruhen lassen kann, man also vorhersehen muss, wie lange die Abarbeitung der Ereignisse wohl dauern wird. Wünschenswert ist ein bedingtes Warten: Das Script soll dann weiterarbeiten oder beendet werden, wenn alle Ereignisse abgearbeitet wurden. Dies kann man auf geschickte Weise erreichen, indem man eine globale Variable definiert und so lange Sleep() mit minimaler Zeitdauer (also eine Millisekunde) aufruft, bis die globale Variable einen bestimmten Wert einnimmt. Das folgende Listing ist Pseudocode. Sie finden konkrete Anwendungsbeispiele für die WSH-Ereignisbehandlung in späteren Kapiteln.
Hinweis zum Listing
' -- Globale Statusvariable Dim fertig ' -- Ereignisbehandlung Sub obj_Ereignis1() ... End Sub Sub obj_Ereignis2() ... If ... Then fertig = True ' Objekt ist fertig! End Sub ' -- Hauptprogramm ready = false Set obj= WScript.CreateObject("ProgID","obj_")
269
9 Die Scripting Hosts
... obj.DoIt ' -- Warten... do while not fertig WScript.sleep 1 loop ... WScript.disconnectobject obj Set obj = Nothing Listing 9.24: Pseudocode-Beispiel für die Behandlung asynchroner Ereignisse im WSH Intelligente In Listing 9.24 werden über das frei wählbare Präfix obj_ die beiden EreignisbehandlungsWarte- routinen an das instanziierte Objekt obj gebunden. Dabei wird die asynchrone Methode schlange
DoIt() gestartet, die später ein Ereignis auslöst. Das WSH-Script erhält direkt nach dem
Methodenaufruf die Kontrolle zurück. Würde sich das Script jetzt beenden, könnte es keine Ereignisse mehr empfangen. Das Script durchläuft so lange eine Schleife mit Sleep(1), bis von dem Objekt obj ein Ereignis2 ausgelöst wurde, das die globale Variable fertig auf True setzt. Ein WSH-Script kann auch aus einer Ereignisbehandlungsroutine heraus mit WScript.Quit() abgebrochen werden. Im obigen Beispiel könnte man für den Fall, dass das Script nach der Abarbeitung der Ereignisse sowieso beendet werden soll, auch die Ereignisbehandlungsroutine obj_Ereignis2() WScript.Quit aufrufen, anstatt der Hauptroutine die Abbruchbedingung zu signalisieren. Wenn jedoch die Hauptroutine danach noch andere Aufgaben zu erledigen hat, muss die Ereignisbehandlungsroutine den Weg der Signalisierung wählen. Natürlich könnte das Script in der Zwischenzeit auch noch andere Dinge erledigen – Hauptsache, es gibt mit einem regelmäßigen Aufruf von Sleep() der WSH-Ereignisbehandlung etwas Luft zum Arbeiten. Sofern das Ereignis Parameter übermittelt, muss dies bei der Definition der Ereignisbehandlungsroutine berücksichtigt werden. In untypisierten Umgebungen wie VBS muss die Anzahl der Parameter stimmen, in typisierten Umgebungen wie VB 6.0/VBA zusätzlich auch die Datentypen der Parameter. Sind diese Voraussetzungen nicht erfüllt, wird die Ereignisbehandlungsroutine weder dem Ereignis zugeordnet noch ausgeführt. Disconnect- WScript definiert auch eine eigene Methode, eine Verbindung zu trennen: Disconnect Object(). Object() Beim WSH wird zusätzlich zu set obj=Nothing dieser Methodenaufruf empfohlen. WScript. GetObject()
Zugriff auf persistente Instanzen WScript.GetObject() ist die analoge Erweiterung der VB-Funktion GetObject() um die WSH-Ereignisbehandlung. Während CreateObject() eine neue Instanz einer COM-Klasse erzeugt, ist mit GetObject() der Zugriff auf bereits bestehende COM-Instanzen einer Klasse möglich. Set obj = WScript.GetObject(Moniker,[ProgID],[Prefix])
270
Windows Script Host (WSH)
9.1.11
Bildschirmmasken für den WSH
Eine Schwäche des Windows Script Host ist die fehlende Möglichkeit, Bildschirmmasken zu Der Dialog generieren und darzustellen. WScript.Echo() und die PopUp()-Methode in der Klasse mit dem Benutzer WSHShell der WSH-Runtime Library (siehe Kapitel 10.1) vermögen nur einfache Dialogfenster mit ausgewählten Schaltflächen darzustellen. VBScript bringt mit InputBox() wenigstens eine eingebaute Methode zur Darstellung einer einzeiligen Texteingabe mit. Von anderen Programmiersprachen wie JScript aus, die eine derartige Funktion nicht haben, können Sie gar keine Benutzereingaben empfangen. Grundsätzlich haben Sie folgende Möglichkeiten, diese Herausforderung zu meistern: 왘 Sie nutzen den Internet Explorer als Plattform zur Darstellung von Bildschirmmasken.
Mit den Möglichkeiten der Microsoft Internet Controls und des HTML Document Object Model (DOM) können Sie HTML-Formulare fernsteuern. 왘 Sie können eigene ActiveX-Steuerelemente mit Visual Basic bzw. der Visual Basic Control Creation Edition erzeugen (siehe Kapitel 19 „Fortgeschrittene Techniken“). 왘 Clevere Programmierer haben den Bedarf inzwischen erkannt und bieten eigene COMKomponenten an, die Bildschirmmasken generieren. Eine Besprechung dieser Oberflächenkomponenten würde den Rahmen dieses Buchs spren- Komponenten anderer gen, daher seien an dieser Stelle nur drei empfehlenswerte Komponenten genannt: Anbieter
왘 WSHForm ActiveX Control ist Freeware von Günther Born [BOR00]. 왘 WSHLiteWeightForm ist Freeware von J. Warrington [WAR00]. 왘 QuickPrompts ist ein kommerzielles Produkt der Firma TopTenSoftware [TOP00]. Diese
Komponente ist die leistungsstärkste der drei genannten.
9.1.12
Sicherheitseinstellungen
Durch den Love-Letter-Virus ist die Sicherheit des Windows Script Host (WSH) in den Brenn- WSHSicherheit punkt des Interesses gerückt. Dieses Kapitel beschäftigt sich mit folgenden Fragestellungen: 왘 Wie kann man WSH-Scripts grundsätzlich deaktivieren? 왘 Wie kann man einzelne WSH-Scripts verbieten? 왘 Wie kann man steuern, unter welchen Benutzerrechten ein Script ausgeführt wird?
Zugriffsrechte Da WSH-Scripts normale Dateien im Dateisystem sind und die Scripting Hosts als eigenständige EXE-Dateien vorliegen, können Sie – sofern Sie das NTFS-Dateisystem verwenden – die Dateisystemsicherheit benutzen, um den Zugriff auf einzelne Scripts bzw. auf den WSH insgesamt zu reglementieren. Zum Start eines Script sind minimal die Rechte wie „Datei lesen“, „Attribute lesen“ und „Berechtigungen lesen“ notwendig (siehe Bild 9.15). „Datei ausführen“ wird nicht benötigt, da die ausführende Instanz beim WSH die wscript.exe bzw. cscript.exe ist (vgl. Teil 2 der Scripting-Kolumne). Um einem Benutzer die Berechtigung zu entziehen, eine WSH-Datei zu starten, müssen Sie also ihm das Recht „Datei lesen“ nehmen, nicht das Recht „Datei ausführen“.
271
9 Die Scripting Hosts
Da der WSH keine eigene Sicherheitskonfiguration besitzt, haben Sie unter Windows 9x/ME bzw. einem FAT-Dateisystem unter der NT-Produktfamilie keine Möglichkeit, die Zugriffsrechte zu regeln. Die NTFS-Sicherheit wirkt nur auf vorhandene Scripts. Sie ist kein Schutz vor Scripts, die Benutzer über Disketten, USB-Sticks übertragen oder die aus dem Netzwerk eingeschleust und von der Festplatte oder einem mobilen Medium ausgeführt werden. Bild 9.15: Minimale NTFS-Sicherheitseinstellungen zum Ausführen eines WSH-Script
Deaktivierung des WSH WSH komplett sperren
Den Zugriff auf den WSH insgesamt können Sie reglementieren, indem Sie die NTFSRechte auf die Dateien WScript.exe und CScript.exe beschränken. In diesem Fall müssen Sie die Startberechtigung über das Recht „Datei ausführen“ steuern. Wenn Sie WSH-Scripts für alle Benutzer (auch lokale Administratoren) verbieten wollen, können Sie diese beiden Dateien auch einfach löschen. Eine noch bessere Möglichkeit zur Deaktivierung des WSH ist der Registrierungsdatenbankschlüssel HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Script Host\Settings\ Enabled. Mit der Zuweisung des Werts 0 ist der Start des WSH nicht mehr möglich – auch nicht, wenn der Benutzer sich WScript.exe oder CScript.exe an einem anderen Ort auf sein System gelegt hat, um die Sicherheitseinstellungen zu umgehen.
272
Windows Script Host (WSH)
Selektive Ausführung mit Software Restriction Policies (SRP) Microsoft hat die Sicherheitseinstellungen des Internet Explorers als Vorbild für ein neues Internet Sicherheitsfeature (verfügbar ab Windows XP) verwendet. Der Internet Explorer erlaubt die Explorer Sicherheit Beschränkung von Programmcode (Scripts, ActiveX-Steuerelemente, Java) auf Basis der Herkunft des Programmcodes (Internet, Intranet, lokale Festplatte etc.). Mit Windows XP wurde dann auch für Programmcode außerhalb des Internet Explorers eine Sicherheitskontrolle eingeführt: Mit Software Restriction Policies (SRP) kann Programmcode auf Basis seiner Herkunft gesperrt werden. Per Lokaler Richtlinie oder Gruppenrichtlinie kann man Sicherheitsbeschränkungen für Programmcode einführen. Der Begriff WinSafer ist ein Alias für SRP. Das Sicherheitssystem der SRP besteht aus genau einer Grundeinstellung und einer beliebigen Anzahl von Regeln. Grundeinstellung In der Grundeinstellung lässt sich zunächst festlegen, ob grundsätzlich jeder Programmcode erlaubt werden soll oder verboten sein soll. Als Programmcode gelten alle Arten von ausführbaren Dateien, einschließlich Scripts. Die Grundeinstellung ist, dass die Ausführung erlaubt ist. Bild 9.16: SRP-Grundeinstellung (Windows Server 2003)
Die Grundeinstellung kann durch weitere Eigenschaften angepasst werden: 왘 Es kann festgelegt werden, ob die SRP auch für DLLs gelten soll. 왘 Es kann festgelegt werden, welche Dateitypen ausführbare Dateien enthalten. 왘 Es kann festgelegt werden, ob die SRP für Administratoren nicht gelten sollen.
273
9 Die Scripting Hosts
Bild 9.17: Feineinstellungen zur SRP (Windows Server 2003)
Bild 9.18: SRP-Einstellungen in Windows Vista
274
Windows Script Host (WSH)
Bild 9.19: Festlegung der Dateitypen (Windows Server 2003)
Regeln Mit der Grundeinstellung „Disallowed“ wäre es unmöglich, Windows zu benut- Alles verbiezen, weil man keine Programme starten kann. Daher ist es notwendig, dass man Regeln ten/einiges erlauben definieren kann, für welche Software die Beschränkung nicht gelten soll. Kriterien für die Beschränkung sind: 왘 Hash-Wert einer ausführbaren Datei 왘 In der ausführbaren Datei enthaltenes Zertifikat gemäß dem Microsoft Authenticode-
Verfahren (vgl. Kapitel 19 „Fortgeschrittene Techniken/Digitale Signatur für Scripts“) 왘 Internet Explorer-Zone 왘 Dateisystempfad 왘 Dateierweiterung In Windows Server 2003 sind vier Regeln vordefiniert, die die wichtigsten Pfade (Windows, System32, Programme) zum Start von Programmen zulassen. Man kann beliebig viele weitere Regeln hinterlegen. Eine Regel kann auch den Start von Software aus einer bestimmten Quelle verbieten. Dies Alles erlaumacht Sinn, wenn die Grundeinstellung „Alles erlauben“ ist. Diese Variante hat den Vorteil, ben/einiges verbieten dass man weniger Regeln hinterlegen muss. Es besteht aber die Gefahr, dass man Quellen übersieht. Beispielsweise kann ein Benutzer eine SRP, die den Start von Anwendungen von Laufwerk D: verbietet, dadurch umgehen, dass er einen anderen Laufwerksbuchstaben der Platte zuordnet, sich mit dem DOS-Befehl subst einen Alias für das Laufwerk anlegt oder eine Laufwerksverknüpfung zu einer lokalen Freigabe auf seinem eigenen Rechner anlegt.
275
9 Die Scripting Hosts
Bild 9.20: Definition einer neuen SRP-Regel (Windows Server 2003)
Man kann bei der SRP nur zwischen „nicht erlaubt“ und „nicht eingeschränkt“ wählen, d.h., die Anwendung startet oder startet nicht. Es ist nicht möglich, einer Anwendung Zugriffsrechte auf einzelne Ressourcen zu geben oder zu entziehen. Dateien und Veränderungen an Dateien erkennen
Hash-Regeln Mit einer Hash-Regel kann man einzelne Anwendungen/Scripts erlauben oder verbieten, unabhängig davon, wo sie liegen. Beim Anlegen einer Hash-Regel muss man eine Datei auswählen. Über diese Datei wird ein Hash-Wert gebildet. Der Algorithmus für den Hash-Wert ist so, dass jede kleinste Änderung an der Datei zu einem anderen HashWert führt. Windows startet die Anwendung nur, wenn der Hash-Wert stimmt. Wenn man zahlreiche Anwendungen und Scripts im Unternehmen verwendet, ist es lästig, für jede dieser ausführbaren Dateien eine Hash-Regel anzulegen. Außerdem muss man bedenken, dass die Hash-Regel nach jeder Änderung an einem Script erneuert werden muss. Es gibt noch keine Möglichkeit, das Anlegen von SRP-Regeln zu scripten. Eine Lösung für diese Herausforderung sind Zertifikatsregeln.
Gruppen von Anwendungen
Zertifikatsregeln Das Microsoft Authenticode-Verfahren ermöglicht es, ausführbare Dateien digital zu signieren. Mit einer Zertifikatsregel kann man definieren, dass mit einem bestimmten digitalen Zertifikat signierte Anwendungen/Scripts ausgeführt werden dürfen. Damit entfällt die Definition für jede einzelne Datei. Im Kapitel 19 „Fortgeschrittene Techniken“ erfahren Sie, wie man WSH-Scripts digital signiert.
276
Windows Script Host (WSH)
Bild 9.21: Anlegen einer Hash-Regel für SRP (Windows Server 2003)
Identität Wie in Kapitel 7 zu „COM“ vorgestellt, bezeichnet die „Identität“ die Frage, unter welchem BenutzerBenutzerkontext ein Script bzw. eine Komponente mit dem Betriebssystem und Anwen- kontext dungen interagiert. Das Script bzw. die Komponente besitzt dann alle Rechte auf Ressourcen, die auch der Benutzer auf diese Ressourcen hat. Ein WSH-Script, das von einem Benutzer manuell gestartet wird, läuft automatisch unter Keine Imperdessen Benutzerkontext. Der WSH selbst unterstützt nicht die Impersonifizierung, d.h. den sonifizierung Ablauf unter einem anderen Benutzerkontext als dem des Aufrufers. Windows bietet jedoch verschiedene Möglichkeiten, eine ausführbare Datei unter einem anderen Benutzerkontext als unter dem des gerade angemeldeten Benutzers laufen zu lassen. Diese Möglichkeiten hat auch ein WSH-Script: 왘 Das Script läuft als geplanter Vorgang im Zeitplandienst, dem ein dezidiertes Benutzer-
konto zugewiesen wurde (nur unter Produkten der NT-Familie). 왘 Sie können das Tool su.exe aus den Resource Kits zu NT 4.0 bzw. das ab Windows 2000
Zeitplandienst su.exe
mitgelieferte runas.exe nutzen, um WScript.exe bzw. CScript.exe unter einem anderen Benutzerkontext auszuführen. 왘 Schließlich steht ab Windows 2000 eine eingebaute Möglichkeit zur Verfügung, bei einer
Windows
Verknüpfung zu einer ausführbaren Datei einen dezidierten Benutzernamen für die Aus- 2000 führung festzulegen.
277
9 Die Scripting Hosts
Bild 9.22: Impersonifizierung für ausführbare Dateien unter Windows 2000
WSH kann Impersonifizierung In all diesen Fällen erfolgt die Festlegung des Benutzerkontexts nicht wech- statisch, d.h. einheitlich für das gesamte WSH-Script. Ein WSH-Script ist – genauso wie seln
andere Scripting Hosts – nicht in der Lage, während seines Programmablaufs den Benutzerkontext zu wechseln. Einige Komponenten, z.B. das Active Directory Service Interface (ADSI), die Windows Management Instrumentation (WMI) und die ISPSignup-Komponente (siehe IIS Resource Kit), unterstützen die Impersonifizierung für die Operationen auf diesen Komponenten. Diese Impersonifizierung gilt dann aber nur für alle Methodenaufrufe in diesen Komponenten. Alle anderen Operationen laufen weiterhin unter dem Benutzerkontext, unter dem das Script gestartet wurde.
Sicherungen vor Einblicken in den Quellcode Die optionale Impersonifizierung in den Komponenten (z.B. ADSI und WMI) erfordert, dass Benutzername und Kennwort im Quelltext des Script stehen. Kennwortsicherung
Ein Kennwort im Klartext irgendwo abzulegen, ist grundsätzlich ein Sicherheitsrisiko – nicht nur für Administrator-Konten. Sofern das Script nicht unbeaufsichtigt laufen muss, sollten Sie daher während der Scriptausführung nach dem Kennwort fragen (z.B. mit InputBox() – siehe Kapitel 8 – oder der Scripting Password-Komponente – siehe Kapitel 10.3). Ungeeignet ist die Kennworteingabe natürlich dann, wenn das Script entweder unbeaufsichtigt laufen soll oder aber im Kontext eines normalen Benutzers gestartet werden soll, dann aber eine Impersonifizierung als Administrator notwendig wird. Dann ist es natürlich keine Alternative, den Benutzer das Kennwort des Administrators eingeben zu lassen.
Script Encoding
Leider kann man auch bei WSH-Dateien nicht zwischen den Rechten „Ausführung“ und „Lesen“ unterscheiden. Das Starten einer WSH-Datei erfordert immer Leserechte auf eine Datei und damit ist auch immer die Einsicht in den Quellcode möglich. Eine Möglichkeit – zumindest gegen weniger erfahrene Benutzer – ist dann nur das Script Encoding (vgl. Kapitel 19 „Fortgeschrittene Techniken“). Dabei wird der gesamte Quellcode einer Datei unkenntlich gemacht. Leider ist das Verfahren mit im Internet kursierenden Tools reversibel.
ASP
Eine wirklich wirksame Sicherung vor dem Betrachten des Quellcodes bietet der WSH überhaupt nicht. Eine grundsätzliche Alternative sind ASP-Scripts: Sie laufen auf einem
278
Windows Script Host (WSH)
Webserver und der Benutzer kann den Quellcode nicht betrachten, sofern er keinen Zugriff auf das Dateisystem des Webservers hat. In der Vergangenheit gab es zwar einige Bugs im IIS, die die Anzeige des Quellcodes ermöglicht haben, doch diese Lücken sollten nach der Sicherheitsinitiative von Microsoft inzwischen gestopft sein.
9.1.13
Sicherheit in Windows Vista
Microsoft hat die Sicherheitseinstellungen in Windows Vista erhöht, was auch den Start von administrativen Scripts einschränkt. Sicherheitswarnung beim Start von Scripts von einem Netzlaufwerk Windows Vista warnt beim Start von Scripts von einem Netzlaufwerk und fordert zur expliziten Bestätigung des Scriptstarts auf. Die Warnung erscheint sowohl beim Start an der Windows-Oberfläche als auch beim Start von der Kommandozeile. Die Warnung erscheint nicht bei Scripts, die im lokalen Dateisystem liegen. Bild 9.23: Warnung beim Start von Scripts in Vista
User Account Protection (UAP) Dem Problem, dass ein fortgeschrittener Benutzer, Administrator oder Entwickler in bisheri- UAPgen Windows-Versionen nur reibungslos arbeiten konnte, wenn er immer als Administrator an Grundlagen seinem Rechner angemeldet war, begegnet Microsoft mit einer neuen Funktion, die „Benutzerkontensteuerung“ (engl. User Account Protection (UAP) oder auch User Account Control (UAC)) heißt. Alle Anwendungen in Vista laufen immer unter normalen Benutzerrechten, auch wenn ein Administrator angemeldet ist. Dies bedeutet, dass viele Scripts (z.B. Starten und Stoppen von Diensten, Benutzerverwaltung) nicht mehr funktionieren können. Anwendungen, die spezielle Unterstützung für UAC/UAP besitzen, präsentieren dem Benut- Nachfragezer ein Dialogfeld, das nachfragt, ob die Anwendung gestartet werden kann. Bei Administra- dialog toren reicht zur Bestätigung ein Mausklick („Consent Prompt“), normale Benutzer müssen Name und Kennwort eines administrativen Kontos eingeben („Credential Prompt“). Erst nach der Bestätigung wird die Anwendung mit administrativen Rechten ausgestattet. Das Verhalten (Nachfrage mit oder ohne Kennworteingabe) kann durch die Systemrichtlinien (Lokale Richtlinien/Sicherheitsoptionen) gesteuert werden.
279
9 Die Scripting Hosts
Bild 9.24: UAP-Bestätigungsanforderung bei normalen Benutzern
Bild 9.25: UAP-Bestätigungsanforderung bei Administratoren
Scripts mit WSH-Scripts erfordern oft Administratorrechte. Ein Administrator wird aber in Vista mit vollen Admin- den bisherigen Strategien, um ein Script zu starten (Doppelklick oder Ausführen im KomRechten ausführen mandozeilenfenster), scheitern. Das Script wird mit der Meldung, dass die Rechte nicht
ausreichen, abbrechen. Ein WSH-Script fragt bei Anwendern nicht nach höheren Rechten, weil man eine Unterstützung für UAC/UAP leider in den WSH nicht eingebaut hat.
280
Windows Script Host (WSH)
Leider sucht man vergeblich im Kontextmenü eines Scriptsymbols nach dem Befehl Als Administrator ausführen. Ein Administrator hat fünf Möglichkeiten, eine Skript dennoch mit vollen Rechten zu starten: 1. Start eines Konsolenfensters mit Administratorrechten. Diese Funktion ist im Kontextmenü des Symbols für die Eingabeaufforderung (sowohl auf dem Desktop als auch im Startmenü oder einem Windows Explorer-Fenster) verfügbar (Als Administrator ausführen). 2. Start des Skripts mit runas.exe. Der Nachteil ist, dass der Administrator dann bei jedem Skriptstart sein Kennwort neu eingegeben muss. 3. Erstellen einer Verknpüfung zu einem Skript, wobei in der Verknüpfung explizit cscript.exe oder wscript.exe dem Skript voranzustellen sind. In den Eigenschaften der Verknüfung kann hinterlegt werden, dass die verknüpfte Anwendung mit vollen Rechten starten soll. 4. Deaktivierung der UAC/UAP-Funktion für alle Skripte durch eine Anwendungskompatibilitätskonfiguration mit dem Application Compatiblity Toolkit. Da man dort die Einstellung nur für cscript.exe und wscript.exe, nicht aber für einzelne Skripte vornehmen kann, ist dies keine befriedigende Lösung. 5. Generelle Deaktivierung der UAC/UAP-Funktion für Administratoren durch Änderung der Systemrichtlinie. Diese Lösung ist nicht zu empfehlen, da damit viel von der erhöhten Sicherheit von Windows Vista außer Kraft gesetzt wird. Bild 9.26: Starten eines Konsolenfensters mit Administratorrechten
Ein Konsolenfenster, das unter Administratorechten läuft, zeigt im Gegensatz zu einem normalen Konsolenfenster auch das Wort „Administrator“ in dem Fenstertitel.
281
9 Die Scripting Hosts
Bild 9.27: Zwei Konsolenfenster mit unterschiedlichen Rechten auf einem Desktop: Nur in der Konsole, die mit Administratorrechten gestartet wurde, kann der Befehl ausgeführt werden.
UAP deaktivieren
Bild 9.28: Ausschalten der Benutzerkontensteuerung für Admistratoren in den Sicherheitsrichtlinien von Windows Vista (MMC-Konsole“ Lokale Sicherheitsrichtlinien“).
282
Die nächste Bildschirmabbildung zeigt, wie man die Benutzerkontenkontrolle für Administratoren deaktivieren kann. Davon ist aber abzuraten, weil damit das Sicherheitssystem von Vista für Administratoren außer Kraft gesetzt wird und die Systeme wieder genauso anfällig für Schädlinge sind, wie es die Vorgänger waren.
DHTML-Scripting im Internet Explorer
9.2
DHTML-Scripting im Internet Explorer
Der Internet Explorer war der erste Active Scripting Host. Seit Version 3.0 unterstützt er nicht nur JavaScript bzw. JScript, sondern auch alle Active Scripting Engines. Das Scripting im Internet Explorer dient der Dynamisierung von Webseiten auf dem Client. Im Gegensatz dazu dynamisiert das im nächsten Kapitel dargestellte ASP auf dem Server.
9.2.1
Grundlagen des Browser-Scripting
Im Internet ist die Verwendung von Scriptsprachen zur Erstellung dynamischer Webanwen- Dynamische dungen inzwischen sowohl auf dem Client als auch auf dem Server populär. Grundsätzliche Webseiten Motivation ist dabei, den Vorteil der Client-Server-Architektur des Webs zu nutzen, indem Verarbeitungsprozesse sinnvoll zwischen Client und Server aufgeteilt werden. Es soll eben nicht die ganze Verarbeitung auf dem Server stattfinden und der Browser soll nicht nur eine verbesserte Variante des „dummen“ Green-Screens aus dem Host-Zeitalter sein – allein mit dem Unterschied, dass er jetzt Farbe darstellen kann und mit der Maus bedient wird. Wenn die Dynamik auf den Server beschränkt ist, bedeutet jede – wenn auch noch so kleine – Veränderung des Bildschirminhalts einen kostspieligen Rundgang zum Server. Anwendungsfälle für clientseitige Webdynamik sind insbesondere: 왘 Prüfung von Eingaben des Benutzers, bevor diese zum Server gesendet werden 왘 Erstellen von Navigationselementen, die Seitenbeschreibungssprachen wie HTML nicht
bereitstellen (z.B. TreeViews) 왘 Animationen im weitesten Sinne. Damit sind Veränderungen des Bildschirminhalts gemeint, die vor allem aus ästhetischen Gesichtspunkten integriert werden sollen. 왘 Inzwischen sind die Möglichkeiten innerhalb des Webbrowsers so groß, dass auch komplette (Business-)Anwendungen im Browser laufen können, die auch stand-alone ohne Webserver arbeiten können.
Einsatzgebiete für BrowserScripting
Wichtigste Voraussetzung für alle clientseitigen dynamischen Techniken ist die Plattform- Kriterien unabhängigkeit – zumindest dann, wenn sich das Angebot an alle Internetnutzer richtet und nicht nur an den vergleichsweise eng umgrenzten Nutzerkreis eines Intranets, dem man Betriebssystem und Browser-Typ von zentraler Stelle diktieren kann. An zweiter Stelle kommt die Sicherheit: Durch eine clientseitige Technik sollen weder die Integrität noch die Vertraulichkeit der Daten und Anwendungen eines Nutzers beeinträchtigt werden. Dabei ist der bekannteste Ansatz für clientseitige Webdynamik die Programmiersprache Java versus Java mit ihrem plattformunabhängigen Bytecode, die in Form von Java-Applets im Browser Scripting zum Einsatz kommt. Es gibt aber Gründe, warum Java in vielen Fällen nicht die erste Wahl ist. Java-Applets sind zu schwergewichtig. Viele Anwendungsfälle lassen sich mit einem Zwei- oder Dreizeiler erschlagen. Der Aufwand, dafür ein Java-Applet zu programmieren, ist vergleichsweise groß. Scriptcode lässt sich im Quelltext in eine HTML-Seite einbetten und ist damit für das Rapid Application Development (RAD) wesentlich besser geeignet. Außerdem ist die Java Virtual Machine, die zur Ausführung des Bytecodes benutzt wird, ein Speicherplatzfresser im Vergleich zu den Scriptinterpretern. VBS ist für die clientseitige Webprogrammierung nicht die erste Wahl, denn es erfüllt die VBS im WebGrundvoraussetzung der Plattformunabhängigkeit nicht. Lediglich der Internet Explorer client – außer in der Macintosh-Version – unterstützt VBS standardmäßig. Die Netscape-Browser
283
9 Die Scripting Hosts
sind erst mit der Zusatzinstallation eines Plug-in der Firma ncompasslabs [NCL00] dazu zu bewegen, VBS zu akzeptieren. Im Rahmen eines Intranets, in dem alle relevanten Benutzer mit dem Microsoft-Browser arbeiten, ist VBS eine gute Wahl, denn Sie können wieder viele Routinen mit „Cut&Paste“ aus VB und den Scripts anderer Scripting Hosts übernehmen. Netscape Navigator
Der Netscape Navigator ist kein Active Scripting Host, auch wenn er das clientseitige Scripting mit JavaScript unterstützt. Der Netscape Navigator kann keine COM-Komponenten ansprechen. Thema ist hier also nur der Internet Explorer, denn es soll eben aufgezeigt werden, wie man hilfreiche COM-Komponenten aus dem Browser heraus anspricht.
Outlook, Integration des Internet Explorers Der Internet Explorer kann in andere AnwendunInterDev und gen integriert werden. Beispiele dafür sind die Entwicklungsumgebungen Frontpage und Frontpage
Visual InterDev sowie Outlook Express und Outlook, die eine Darstellung von HTMLEHMails ermöglichen. Mit Hilfe des Microsoft Internet Control können Sie die Browser-Funktionalitäten in eigenen Anwendungen bereitstellen. In all diesen auf dem Internet Explorer basierenden Umgebungen ist auch die Ausführung von in HTML-Seiten eingebetteten Scripts möglich.
DHTML, Browser-Technologien Browser-Scripting ist ein Teil der Technologie, die von einigen CSS, DOM Herstellern – so auch von Microsoft – unter dem Begriff Dynamic HTML (DHTML)
zusammengefasst wird. DHTML umfasst: 왘 die Seitenbeschreibungssprache HTML 왘 die Formatierungssprache Cascading Style Sheets (CSS) 왘 das Document Object Model (DOM)
DOM ist ein vom World Wide Web Consortium (W3C) [DOM00] standardisiertes Objektmodell für den Zugriff auf Dokumente vom Scriptcode aus. Auch HTML und CSS sind vom W3C standardisiert. Natürlich gibt es – wie sollte es auch anders sein – ein Microsoft DHTML, eine Erweiterung der standardisierten Form. Zu Microsoft DHTML gehören auch noch die Techniken Data Binding (nicht Bestandteil dieses Buchs) und DHTML-Scriptlets (kurze Erläuterung in Kapitel 7).
9.2.2
Einbindung von Scriptcode
Scriptcode kann in eine HTML-Seite auf drei verschiedene Weisen eingebunden werden: Scriptblock
1. In einem speziellen Scriptblock innerhalb der Seite: ...
Externe Scriptdateien
2. In Form einer externen Datei, die von dem Browser zur Ladezeit mitgeladen und verknüpft wird:
284
DHTML-Scripting im Internet Explorer
3. In Form einer in ein Tag eingebundenen Ereignisbehandlungsroutine:
Inline in HTML
In den Fällen 1 und 2 wird ein Script durch das Tag von dem üblichen Quelltext abgegrenzt. Das -Tag hat hier in DHTML seinen Ursprung. Microsoft hat sich dieses Tag später auch im Rahmen anderer Scripting Hosts zu Eigen gemacht. Achtung: Im Gegensatz zu allen anderen Active Scripting Hosts ist VBS im Internet Explorer nicht die Standardsprache, sondern JScript. Sie müssen es also explizit definieren, wenn Sie VBS nutzen wollen. Die Beispiele sind zunächst allesamt reine clientseitige Beispiele. Da keine Verknüpfung client- und serverseitiger Programmlogik stattfindet, brauchen Sie keinen Webserver, um die Beispiele zu testen. Erstellen Sie einfach eine Textdatei mit der Erweiterung .htm (oder .html) in Ihrem Dateisystem und laden Sie diese in den Webbrowser. Um eine HTML-Datei im Internet Explorer anzuzeigen, haben Sie folgende Möglichkeiten: 왘 Drag&Drop der Datei in das Internet Explorer-Fenster 왘 Doppelklick auf die Datei (sofern der Internet Explorer Ihr Standardbrowser ist) 왘 Eingabe des Pfads zu der Datei in der URL-Zeile 왘 Auswahl der Datei im Datei/Öffnen-Dialog
9.2.3
Hello World im Browser
Wie üblich soll das erste Beispiel nicht mehr leisten, als das allseits bekannte Dialogfenster Erstes mit dem Gruß an die Welt auszugeben. Der komplette Quellcode der Webseite liegt inner- Beispiel halb eines -Tag. Darin eingebettet ist ein -Tag mit einer einsamen Befehlszeile. Die Position des Scriptblocks ist in diesem Fall entscheidend für die Reihenfolge der Ausgabe. Der Browser gibt zunächst „Diese Seite sagt Ihnen Hallo...“ aus, danach erscheint das Dialogfenster und am Ende wird „Fertig.“ an die obige Ausgabe angehängt. Diese Seite sagt Ihnen HALLO... Msgbox "Hello World!" Fertig. Listing 9.25: DTHML-Seite für Hello World
Es kann beliebig viele Scriptblöcke in einem Dokument geben. Sofern diese Scriptblöcke Mischung nicht wie weiter unten beschrieben an ein Ereignis gebunden sind, werden sie sequenziell von HTML und Script ausgeführt. HTML-Ausgaben zwischen den Scriptblöcken werden ebenso sequenziell dargestellt. In Scriptblöcken enthaltene Unterroutinen werden natürlich nicht sequenziell ausgeführt, sondern nur dann, wenn sie aufgerufen werden.
285
9 Die Scripting Hosts
Erste Ausgabe...
Msgbox "Erste Dialogbox." Zweite Ausgabe...
Msgbox "Zweite Dialogbox." Dritte Ausgabe...
Msgbox "Dritte Dialogbox." Listing 9.26: Script- und HTML-Blöcke können sich abwechseln. HTML-Syntax
Dieses Buch kann keinen Kurs in Hypertext Markup Language (HTML) enthalten. Wenn Sie nicht mit HTML vertraut sind, mögen Ihnen die folgenden Hinweise helfen: 왘 Die „Befehle“ in HTML heißen Tags. 왘 Ein Tag ist immer durch < und > von dem Inhalt abgegrenzt. 왘 Der Befehlsteil des Tag ist nicht case-sensitive. Aus Gründen der Übersichtlichkeit
schreibt man den Tag-Namen aber oft nur in Großbuchstaben. 왘 Ein Zeilenumbruch im Quelltext ist kein Zeilenumbruch in der Ausgabe. Um einen
Umbruch zu erzeugen, setzen Sie die Tags (einfacher Zeilenumbruch) oder
(Absatz).
9.2.4
Sicherheitseinstellungen
Gefährdung Ein Script im Internet Explorer läuft stets unter der Identität des angemeldeten Benutzers. durch Viren Allerdings kann ein Script nicht automatisch alle Aktionen ausführen, die der Benutzer auszuund Würmer
führen vermag. Es gibt detaillierte Sicherheitseinstellungen für die Zugriffsrechte des Scripts wie in keinem anderen Scripting Host. Besondere Bedeutung beim Browser Scripting kommt dem Schutz des Browser-Nutzers vor der Gefährdung der Geheimhaltung und Integrität seiner Daten zu. Da jede (aus dem Internet geladene) HTML-Seite Script enthalten kann, besteht prinzipiell die Gefahr, bösartigen Programmcode durch den Aufruf einer Internetseite zu starten. Dies gilt auch für den Aufruf von E-Mails in E-Mail-Programmen wie Outlook 2000 und Outlook Express 5.0, die in HTML formatierte E-Mails mit Hilfe der gleichen Komponenten wie der Internet Explorer darstellen. Auch in HTML-formatierten E-Mails enthaltener Scriptcode wird ausgeführt. Dass Script- und Makrosprachen sich zur Erstellung gefährlicher Viren und E-Mail-Würmer eignen, haben die Viren Melissa und Love-Letter gezeigt (vgl. [SCH00c]).
Zum Schutz vor derartigem Missbrauch bieten Scriptsprachen wie VBScript und JScript bewusst keinerlei Funktionen zum Zugriff auf Systeminformationen, Dateisystem und Netzwerkfunktionen. Solche Funktionalitäten können nur durch COM-Komponenten bereitgestellt werden, die einem besonderen Schutz unterliegen. Internet- Die Sicherheitseinstellungen des Internet Explorers, die auch für alle Programme gelten, die optionen/ Funktionen des Internet Explorers nutzen, können über Extras/Internetoptionen/Sicherheit Sicherheit
286
DHTML-Scripting im Internet Explorer
innerhalb des Browsers oder über Systemsteuerung/Internetoptionen/Sicherheit aus dem Windows-Start-Menü heraus erreicht werden. Sicherheitszonen Es gibt verschiedene vordefinierte Zonen und Sicherheitsstufen. Der Zonen Internet Explorer achtet darauf, woher ein Script geladen wird. Dabei werden fünf Zonen unterschieden: 왘 Arbeitsplatz (Zone 0) 왘 lokales Intranet (Zone 1) 왘 vertrauenswürdige Sites (Zone 2) 왘 Internet (Zone 3) 왘 eingeschränkte Sites (Zone 4)
Diese Zonen finden Sie im IE5 unter Extras/Internetoptionen/Sicherheit und in der Registrierungsdatenbank unter HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Current Version\Internet Settings\ Zones. Die Zone 0, Arbeitsplatz, wird normalerweise nicht in den Internet Explorer-Sicherheitsoptionen angezeigt. Um diese Zone anzuzeigen, muss der Schlüssel HKEY_CURRENT_ USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\ 0\flags auf 1 gesetzt werden. Für alle Benutzer ändert das auf der CD enthaltene WSH-Script anzeige_ der_Zone0.vbs diese Einstellung. In Outlook 2000 und Outlook Express kann jeweils unter den Sicherheitsoptionen fest- Zonen in den gelegt werden, ob für eingehende HTML-E-Mails die Zone „Internet“ oder „eingeschränkte E-Mail-Programmen Sites“ gelten soll (siehe [SCH00c]). Sicherheitsstufen In den Internetsicherheitsoptionen werden zu jeder Zone vier vor- Sicherheitsdefinierte Sicherheitsstufen angeboten: hoch, mittel, niedrig und sehr niedrig. Es gibt eine stufen Vielzahl von Einzeleinstellungen, wobei jede der vier vordefinierten einer bestimmten Kombination der Einzeleinstellungen entspricht. Sie gelangen zu den Einzeleinstellungen über die Schaltfläche Stufe anpassen. In den meisten Sicherheitseinzeleinstellungen gibt es die Punkte Aktivieren, Deaktivieren und Eingabeaufforderung (siehe Bild 9.29). Bild 9.29: Sicherheitseinzeloptionen im Internet Explorer 5.0
287
9 Die Scripting Hosts
Scripting ist Aktivierung des Active Scripting Im Standard ist für alle Zonen und alle Sicherheitsim Standard stufen das Scripting aktiviert. Sie können dies jedoch über die Anpassung der Sicherheitserlaubt
stufen über den Punkt Scripting/Active Scripting deaktivieren bzw. eine Einzelbestätigung des Benutzers verlangen.
Sicherheit
Sicherheitseinstellungen für COM-Komponenten Ob bei aktiviertem Scripting aus einem Script heraus eine konkrete COM-Klasse instanziiert werden kann, hängt von drei Faktoren ab: 왘 Speicherort des Script (es gelten die oben genannten Zonen) 왘 Komponentenkategoriezugehörigkeit der Klasse 왘 Einstellungen für die Sicherheitszone entsprechend dem Speicherort des Script
MINFU
Sichere Komponenten
Im Internet Explorer ist stets von ActiveX-Steuerelementen die Rede. Dies ist jedoch der falsche Begriff: Die Einstellungen betreffen alle automatisierungsfähigen COM-Komponenten, nicht nur Steuerelemente mit GUI. Komponentenkategorie Der Internet Explorer unterscheidet zwei Arten von COMKlassen: 왘 COM-Klassen, die für Scripting sicher sind 왘 COM-Klassen, die nicht sicher sind
Was ist sicher?
Sicher bedeutet dabei nicht nur, dass die Klasse an sich kein Schädling ist, sondern auch, dass die Klasse nicht dazu missbraucht werden kann, Schaden anzurichten. Ein Beispiel für eine sichere Komponente ist die Klasse Scripting.Dictionary, die der temporären Speicherung von Informationen dient. Die Klasse Scripting.FileSystemObject, die den Zugriff auf das Dateisystem eröffnet, wird dagegen als nicht sicher registriert.
Zuordnung Der Internet Explorer ist selbst nicht in der Lage zu entscheiden, ob eine COM-Klasse sicher über die ist oder nicht. Die Einstufung ist abhängig von der Zuordnung zu den beiden KomponenKomponentenkategorie tenkategorien „Safe for Initialization“ {7DD95802-9882-11CF-9FA9-00AA006C42C4} und
„Controls safely scriptable“ {7DD95801-9882-11CF-9FA9-00AA006C42C4}. Diese Zuordnungen kann eine Klasse natürlich bei ihrer Registrierung selbst vornehmen. Ein Administrator kann jederzeit in der Registrierungsdatenbank einstellen, ob eine COMKlasse als sicher gelten soll oder nicht. Beispielsweise macht die folgende Registrierungsdatei die erwähnte Klasse Scripting.FileSystemObject sicher. Bitte beachten Sie, dass die angegebene CLSID versionsabhängig ist. Prüfen Sie also vorher, welche CLSID die bei Ihnen installierte Version der Scripting Runtime Library ist (siehe Kapitel 10.2). REGEDIT4 [HKEY_CLASSES_ROOT\CLSID\{0D43FE01-F093-11CF-894000A0C9054228}\Implemented Categories\{7DD95801-9882-11CF-9FA9-00AA006C42C4}] @="" Listing 9.27: Aufnahme der Klasse Scripting.FileSystemObject in die Menge der als sicher geltenden COM-Klassen
288
DHTML-Scripting im Internet Explorer
Achtung: Wenn Sie diese Änderung vornehmen, könnten aus einer HTML-Seite oder HTML-E-Mail heraus Dateien auf Rechnern gelesen oder verändert werden. Diese Änderung sollte einhergehen mit der Deaktivierung von Scripting für alle Zonen außerhalb des Arbeitsplatzes. Sicherheitseinzeleinstellungen für COM-Komponenten Im Browser sind die Sicher- Internetheitseinstellungen je Komponentenkategorie und Zone konfigurierbar (siehe Bild 9.29). Dabei optionen ist einstellbar, ob COM-Objekte 왘 generell instanziiert werden dürfen, 왘 generell nicht instanziiert werden dürfen, 왘 nur nach Rückbestätigung durch den Benutzer instanziiert werden dürfen.
Ist die Instanziierung generell verboten oder wurde sie vom Benutzer abgelehnt, dann führt jeder Aufruf von CreateObject() zu dem Fehler „ActiveX-Komponente kann kein Objekt erstellen.“. Leider ist dies die gleiche Fehlermeldung, die auch erscheint, wenn der Klassenname nicht stimmt oder die Registrierung der Komponente fehlerhaft ist. Standardeinstellungen Im Auslieferungszustand sind in allen Stufen nur die sicheren StandardeinSteuerelemente aktiviert. Außer in der Stufe „sehr niedrig“ sind die nichtsicheren Steuerele- stellungen mente („ActiveX-Steuerelemente initialisieren und ausführen, die nicht sicher sind“) deaktiviert. Die Deaktivierung der nichtsicheren Steuerelemente gilt aber auch für Zone 0, Arbeitsplatz. Auch Sie als Administrator oder Programmierer können also von Ihrer lokalen Festplatte keine Automatisierungslösungen auf Basis von DHTML-Scripts nutzen, da diese in der Regel nichtsichere Steuerelemente verwenden. Um dies für alle Komponenten für die lokale Ausführung zu aktivieren, benötigen Sie nachfolgende Registrierungsdatenbankeinstellungen. [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\0] @="" "1201"=dword:00000000 "1405"=dword:00000000 Listing 9.28: Aktivierung aller COM-Komponenten in der Zone Arbeitsplatz [CD:/install/hosts/ ie/zone0_alle_Komponenten_aktivieren.reg]
Die generelle Aktivierbarkeit der Klasse Scripting.FileSystemObject durch die Änderung der Komponentenkategoriezugehörigkeit oder der Sicherheitszoneneinstellungen für alle Browser-Benutzer in Ihrem Netzwerk zuzulassen, ist kritisch. Denn während viele Benutzer bereits das Bewusstsein haben, dass eine lokal gestartete EXE-Datei prinzipiell auf alles zugreifen kann, vermuten die Benutzer beim Start einer HTML-Datei keine Gefahr. Mit der Beibehaltung dieser Beschränkung verbauen Sie sich aber auch nicht ganz die Möglichkeit, Automatisierungslösungen auf Basis von HTML-Scripts an Ihre Benutzer auszuliefern. Die in Kapitel 9 vorgestellten HTML-Applications (HTAs) unterliegen nicht den Sicherheitseinstellungen des Browsers.
289
9 Die Scripting Hosts
Sicherheitseinstellungen ab Windows XP Service Pack 2 Mit Windows XP Service Pack 2 (gilt auch Windows Server 2003 Service Pack 1 und Windows Vista) hat Microsoft eine Verschärfung der Sicherheitseinstellungen des Internet Explorers eingeführt, ohne dabei die Versionsnummer des Internet Explorers zu erhöhen. Bei Webseiten, die Scripts oder ActiveX-Steuerelemente enthalten, zeigt der Internet Explorer eine Sicherheitsleiste. Durch einen Klick muss die Ausführung der dynamischen Elemente explizit bestätigt werden. Bild 9.30: Sicherheitsleiste im Internet Explorer (hier in Windows Server 2003 R2)
Die Blockade für Scripts wirkt auch für Dateien in der Sicherheitszone „Arbeitsplatz“, d.h. für Dateien auf dem lokalen System. Diese Blockade kann nicht in der Registerkarte Sicherheit, sondern in der Registerkarte Erweitert in der dortigen Rubrik Sicherheit ausgeschaltet werden (siehe Bildschirmabbildungen). Bild 9.31: Ausschalten der Sicherheitsleiste im Internet Explorer 6.0 unter Windows Server 2003 R2
290
DHTML-Scripting im Internet Explorer
Bild 9.32: Ausschalten der Sicherheitsleiste im Internet Explorer 7.0 unter Windows Vista
9.2.5
DOM-Ereignisbehandlung
Jedes Element eines Dokuments löst eine Vielzahl von Ereignissen im Document Object DOMModel aus (z.B. bei Mausklick, Mausbewegung, Änderungen), die mit einer Ereignis- Ereignisse behandlungsroutine belegt werden können. Es gibt verschiedene Möglichkeiten zur Definition einer DOM-Ereignisbehandlungsroutine: 왘 Inline-Ereignisbehandlung: Das Element kann mit einem Attribut versehen werden,
Ereignis-
das den Namen des Ereignisses trägt. Der diesem Attribut zugewiesene Wert wird aus behandlungsProgrammcode ausgeführt, wenn das Ereignis eintritt. Wenn mehr als ein Befehl ausge- routine führt werden soll, steht hier üblicherweise der Name einer in einem Scriptblock implementierten Unterroutine. Es ist aber in VBS auch möglich, jeweils durch Doppelpunkte getrennt weitere Befehle anzugeben:
왘 Externe Ereignisbehandlung: Wenn dem Element ein eindeutiger Name über das Attri-
but ID zugewiesen wurde, dann gibt es zwei weitere Möglichkeiten zur Bindung einer Ereignisbehandlungsroutine an ein Ereignis: 왘 Über eine Unterroutine im Stil einer Ereignisbehandlungsroutine: Sub ID_EREIGNISNAME
Dabei entspricht id der ID des Elements. 왘 Über einen Scriptblock mit den zusätzlichen Attributen for und event:
Dabei folgen nach for= die ID des Elements und nach event= der Ereignisname.
291
9 Die Scripting Hosts
Beispiele
Beispiele für die Ereignisbehandlung In dem nachfolgenden Listing werden alle vier Varianten gezeigt. Das Ergebnis ist für den Anwender immer das Gleiche: Er erhält nach dem Klicken ein Dialogfenster. Bei den Inline-Ereignishandlern ist es grundsätzlich notwendig, die Scriptsprache anzugeben, sofern nicht die Standardsprache JScript verwendet wird. Dass Variante 2 auch ohne diese Angabe funktioniert, ist darauf zurückzuführen, dass der Befehl zum Aufruf einer Unterroutine in VBS und JScript gleich ist. Alternativ können Sie auch einen leeren Scriptblock der Form
an den Anfang des Dokuments setzen: Damit stellen Sie die Standardsprache auf VBS um. Inline... (kompletter Befehl)
Inline... (Funktionsaufruf)
Extern... (über Prozedurnamen)
Extern... (über -Tag)
SUB sageHallo1 msgbox "Hello World – Variante 2" END SUB SUB Link2_OnClick msgbox "Hello World – Variante 3" END SUB msgbox "Hello World – Variante 4" Listing 9.29: Verschiedene Möglichkeiten für die Ereignisbehandlung in DHTML
Die obige Bemerkung zu Variante 2 hat Ihnen schon gezeigt: Es ist auch im Internet Explorer möglich, verschiedene Scriptsprachen zu mischen. // ----- Unterroutine in JScript function jadd(a,b) { return(a+b) } ' ------ Hauptprogramm in VBScript ' JScript zur Addition nutzen x = 5 y = 6
292
DHTML-Scripting im Internet Explorer
Ergebnis = jadd(x,y) msgbox x & " + " & y & " = " & ergebnis Listing 9.30: Mischung verschiedener Scriptsprachen in einer HTML-Seite
Allerdings existiert eine Begrenzung hinsichtlich der Ebenentiefe bei Rekursionen, wenn sich dabei Funktionen aus zwei verschiedenen Sprachen gegenseitig aufrufen. Es sind dann maximal vierzehn Wechsel der Sprache innerhalb einer Rekursion erlaubt. function f1 (x) { If (x > 1) f2 (x-1); } function f2 (y) If (y > 1) Then f1 y-1 end function Msgbox "14 Rekursionen..." f1(14) ' ist OK Msgbox "15 Rekursionen..." f1(15) ' Stack overflow!! Listing 9.31: Veranschaulichung des Rekursionsproblems
9.2.6
Eingebaute Objekte (Intrinsic Objects)
In den bisherigen Beispielen leben HTML und Script zwar im selben Haus, bemalen aber Eingebaute verschiedene Wände: Die Ausgaben von HTML landen im Browser-Fenster, das Script muss Objekte sich mit schlichten Dialogfenstern begnügen. Dabei haben Scripts im Internet Explorer zwei mächtige Objektmodelle über Eingebaute Objekte im Zugriff: 왘 das Webbrowser-Objektmodell für den Zugriff auf den Browser 왘 das Document Object Model (DOM) für den Zugriff auf den dargestellten Inhalt („das
Dokument“) Zugriff auf das Webbrowser-Objektmodell Das Eingebaute Objekt für den Zugriff auf das Webbrowser-Objektmodell heißt Window. WindowObjekt Das Objekt Window ermöglicht u.a. den Zugriff auf: 왘 das DOM des gerade gezeigten Dokuments (Unterobjekt document), 왘 die URL, der zum aktuellen Dokument führte (Unterobjekt location); über dieses Unter-
objekt kann die aktuell gezeigte Seite auch verändert werden (location. assign(URL)), 왘 die Eigenschaften der Bildschirmdarstellung (height, width, colordepth etc.), 왘 die Navigationshistorie (Back, Forward etc.),
293
9 Die Scripting Hosts
왘 Version und Funktionen des Browsers über die Unterobjekte Navigator und client-
Information, 왘 Befehle des Browsers (Open, Print, Close etc.), 왘 die Zwischenablage (Unterobjekt clipboarddata), 왘 einfache Dialogfenster (Alert für eine MessageBox, Confirm für eine Inputbox), 왘 Ereignisse des Browsers (z.B. onBeforePrint(), onAfterPrint(), onLoad(), onError(),
onResize() etc.) window.close() warnt vor der Ausführung: „Die angezeigte Webseite versucht, das Fens-
ter zu schließen. Soll das Fenster geschlossen werden?“ Mehr über dieses Objektmodell erfahren Sie im Kapitel „Internet Explorer Controls“. Zugriff auf das Document Object Model (DOM) document- Den Zugriff auf das DOM ermöglicht das Eingebaute Objekt document. document ist gleichObjekt zeitig über window.document erreichbar, so dass folgende Bedingung immer erfüllt ist:
If document is window.document Then msgbox "immer wahr!"
Wenngleich eng mit dem Explorer verbunden, so ist das DOM dennoch auch von anderen Anwendungen aus verwendbar. Aus Platzgründen kann das DOM in diesem Buch nicht ausführlicher beschrieben werden. Das DOM wird später besprochen. Der nachfolgende Abschnitt stellt nur kurz die wichtigsten Ausgabemethoden des DOM vor. document. Ausgaben direkt ins Dokument Der Internet Explorer ist ein Werkzeug zur Darstelwrite() und lung von Dokumenten, die auch dynamisch erzeugt werden können. In der Regel wollen Sie WriteLn()
Ihre Ausgaben nicht per Dialogfenster erzeugen, sondern direkt in das Dokumentenfenster schreiben.
Das document-Objekt bietet zur Ausgabe die Methoden Write() und WriteLn() an. Damit wird eine Ausgabe an der gerade aktuellen Stelle im Dokument erzeugt. Im Gegensatz zu Write() erzeugt WriteLn() auch einen Zeilenumbruch, allerdings im Quellcode. Es wird kein - oder
-Tag erzeugt! say() und saynb()
Sie sollten neben einer Methode say() auch ein saynb() definieren, das keinen Zeilenumbruch in der Ausgabe erzeugt. Die Standardroutine say() sollte einen Zeilenumbruch setzen, um die Routine semantisch äquivalent zu Scripting Hosts zu halten, die automatisch einen Zeilenumbruch nach jedem Ausgabebefehl erzeugen. Das nb in saynb() steht für „no break“. ' ### Ausgabe ohne Zeilenumbruch Sub saynb(s) document.write s End Sub ' ### Ausgabe mit Zeilenumbruch Sub say(s) document.write s & "" End Sub Listing 9.32: Ausgabefunktionen für IE via DOM
294
DHTML-Scripting im Internet Explorer
Diese beiden Routinen sind in der Funktionsbibliothek WS_ieLIB enthalten [CD:/code/ hosts/ie/WS_ieLIB.vbs].
WS_ieLIB
Das folgende Script testet die Ausgaben mit say() und saynb(). Es zeigt auch, dass eine Aus- Beispiel gabe an einer gezielten Position erzeugt werden kann. Jedes HTML-Element, das ein IDAttribut besitzt, ist aus der Sicht von DHTML ein Objekt. Es kann entweder über den bei id vergebenen Namen direkt verwendet werden oder aber über die document.all-Objektmenge, wobei hier der Name als Zeichenkette übergeben wird. Das Attribut innerhtml ändert den ganzen Inhalt des Tag. Mit der Methode insertAdjacentHTML() wird an einer zu definierenden Stelle (hier: „beforeEnd“) Text an ein Tag angefügt. Auch können einzelne Attribute von benannten Elementen (hier das src-Attribut der -Tags mit den Namen Foto und Logo) geändert werden, um die Anzeige zu beeinflussen.
' --- Ausgabe an aktueller Position say "- Unabhängiger Technologieberater, Softwarearchitekt, Fachjournalist, Dozent" say "
- Buchautor bei Addison Wesley und Microsoft Press" saynb "
- Ständiger Mitarbeiter der Zeitschrift 'iX', " say "'DotNetPro' und 'Windows IT Pro'" if date > #5/1/2000# then say "
- Herausgeber 'Praxishandbuch Windows 2000' (Interest Verlag)" if date > #5/1/2003# then say "
- Herausgeber 'Praxishandbuch Windows Server 2003' (Interest Verlag)" say "
- Sprecher auf nationalen und internationalen Fachkonferenzen" ' --- Ausgabe an einer gezielten Position Ueberschrift.innerhtml = "Aktuelle Tätigkeiten von Dr. Holger Schwichtenberg"
Stand: Kontakt: ' --- Ausgabe an einer gezielten Position document.all("Kontakt").insertAdjacentHTML "beforeEnd","
[email protected]" document.all("Stand").insertAdjacentHTML "beforeEnd",date for a = 1 to 5 ' Leerzeichen einfügen document.all("Stand").insertAdjacentHTML "beforeEnd"," " next
295
9 Die Scripting Hosts
' --- Attribut setzen, um Foto anzuzeigen foto.src="hs.jpg" logo.src="itvlogo.jpg" logo.outerHTML = "" & logo.outerHTML & "" Listing 9.33: Ausgaben ins Browser-Fenster mit Hilfe des Document Object Model [CD: /code/hosts/ie/domausgabe.htm] Bild 9.33: Bildschirmabbildung der Seite domAusgabe.html
9.2.7
Zugriff auf externe COM-Komponenten
Die Methode CreateObject() steht generell auch beim Internet Explorer Scripting zur Verfügung. Allerdings unterliegt die Verfügbarkeit des Befehls den Sicherheitseinstellungen des Browsers. Create Instanziierung mit CreateObject() Die Klasse Scripting.FileSystemObject wird im Object() nachfolgenden Beispiel dazu verwendet, eine Datei anzulegen, zu beschreiben und anschlie-
ßend wieder zu löschen. Der Löschbefehl kann aber auch ein Verzeichnis betreffen, das es vorher schon gab, z.B. Ihr Datenverzeichnis! Diese Seite testet COM im IE COM-Objekt wird erzeugt...
const dateiname = "d:\buch\spionage.txt" set fso = CreateObject("Scripting.FileSystemObject") set tx = fso.CreateTextFile(dateiname) tx.writeLine "Hier speichere ich jetzt Daten über Sie..." tx.close document.write "Eine Datei wurde angelegt!
" fso.DeleteFile dateiname
296
DHTML-Scripting im Internet Explorer
Die Datei wurde wieder gelöscht!
Ein böser Geselle hätte mehr machen können...!
Listing 9.34: Instanziierung einer COM-Klasse im DHTML-Script
Bitte beachten Sie, dass diese Gefahr aber nur besteht, wenn ein Benutzer die Sicherheitseinstellung im Browser herabsetzt oder die Klasse Scripting.FileSystemObject in der Registrierungsdatenbank als sicher markiert ist. Statische Objekte Der Internet Explorer unterstützt ebenso wie der WSH statische Objekte. Es wird dasselbe Tag () verwendet. Allerdings gibt es nicht die Möglichkeit, eine ProgID anzugeben; die Klasse muss über eine CLSID spezifiziert werden. Die folgende Codezeile zeigt die Einbindung der Klasse Scripting.FileSystemObject:
Das -Tag wird im Internet Explorer auch zur Einbindung visueller ActiveX-Steuerelemente verwendet. Daher besitzt es auch Attribute wie BORDER, VSPACE, HEIGHT und WIDTH, die aber hier nicht von Bedeutung sind. Ein -Tag kann Unterelemente enthalten, mit denen Attribute des instanziierten Objekts nach der Instanziierung gesetzt werden, z.B.
Bindung mit GetObject() Es ist im Internet Explorer unterbunden, auf bestehende GetObject() Instanzen mit GetObject() zuzugreifen. Diese Funktion ist aus Sicherheitsgründen unabhängig von der Sicherheitseinstellung nicht verfügbar. Mit Hilfe der Komponente ADsFactory (vgl. Kapitel „Komponenten/ADSI“) haben Sie die Möglichkeit, dies zu umgehen. Bei der Ausführung eines DHTML-Script innerhalb der Entwicklungsumgebung Visual InterDev InterDev funktioniert die Funktion GetObject() jedoch. Sie sollten Ihre Scripts also immer mit einem richtigen Browser testen. Ereignisbehandlung Der Internet Explorer unterstützt die Behandlung von Ereignis- COMsen, die durch COM-Objekte ausgelöst wurden. Dies ist nicht zu verwechseln mit der Ereignisse Behandlung von Ereignissen aus dem Document Object Model. Voraussetzung für die Behandlung von COM-Ereignissen ist, dass die Instanz als statisches Objekt erzeugt wurde.