Eigentlich ist es ja eine Schande. Da gibt es zum Beispiel das schöne FileSystemObject - und eine Datei- oder Verzeichnisliste können Sie nur auf Umwegen und nur mit minimalster gestalterischer Freiheit ausdrucken: Liste in Datei schreiben, Datei über Shell-Funktionen auf dem Standard-Drucker ausdrucken. Wie wäre es mit einem Printer-Objekt fürs Windows-Scripting, das Ihnen die Möglichkeit bietet, Texte und sogar Grafiken in nahezu beliebiger Gestaltung zu drucken?
Nun, ich kann und will Ihnen nicht zu viel versprechen, jedenfalls nicht mehr, als... ja, als das in Visual Basic eingebaute Printer-Objekt zu leisten imstande ist. Aber das ist schon eine ganze Menge, weitaus mehr, als Sie wahrscheinlich mit den Möglichkeiten von VBScript im Windows Scripting Host überhaupt ausnutzen werden können.
Leider geht es nicht, das VB-Printer-Objekt per CreateObject direkt zu instanzieren und zu verwenden. Es ist kein echtes COM- bzw. ActiveX-Objekt. Innerhalb einer Visual Basic-Anwendung steht das Printer-Objekt jedoch jederzeit frei zur Verfügung. Was also fehlt, ist also eine solche VB-Anwendung, genauer gesagt, eine mit VB erstellte ActiveX-Komponente, der das Printer-Objekt sowohl instanziert und für den Zugriff per Scripting zur Verfügung stellt, als auch dessen Eigenheiten mit Hilfe von ein paar Hilfsfunktionen umschifft.
Die sozusagen eigenartigste Eigenheit des Printer-Objekts steckt hinter seiner wohl am häufigsten benötigten und verwendeten Methode, der Print-Methode in der "klassischen" Basic-Syntax. Ohne "Print" kann kein Text ausgegeben werden - und diese Methode können Sie von der Scripting-Seite aus leider nicht benutzen. Sie könnten lediglich Linien, Kästen und Kreise aufs Papier malen lassen und Bilder ausgeben.
Halt, nein, letzteres ist nicht richtig - in Punkto Bilder tritt die zweite Eigenheit des Printer-Objekts zutage. Was allerdings so auch wieder nicht stimmt. Das Printer-Objekt kann nichts dafür, dass es nur Bilder verarbeiten kann, die ihm als StdPicture-Objekt, einem Standard-COM-/OLE-Objekt übergeben werden. Hier liegt das Problem bei VBScript bzw. dem Windows Scripting Host - diese können leider nicht mit dem StdPicture-Objekt richtig umgehen (Beim StdFont-Objekt scheinen da keine Stolpersteine im Weg zu liegen). Es mag sein, dass es irgendwelche Hintertüren gibt, die aber die üblichen Scripting-Horizonte übersteigen würden. Eine zusätzliche Aufgabe für den Printer-ActiveX-Server wäre also, dafür zu sorgen, dass Sie Bilder laden und nach Ihren Layoutvorstellungen über das Printer-Objekt ausgeben können.
Die Hauptaufgabe ist schnell erledigt. In einer Eigenschaft wird die VB-Printers-Sammlung zur Verfügung gestellt, über die alle installierten Drucker ermittelt werden können. In einer zweiten Eigenschaft wird das Printer-Objekt selbst bereitgestellt. Sie können über diese Objekt-Referenz nahezu alles machen, was Sie mit dem Printer-Objekt in VB machen können (soweit der Sprachumfang von VBScript dies ermöglicht) - schließlich ist es ja das originale VB-Printer-Objekt.
Public Property Get Printer() As Object
Set Printer = VB.Printer
End Property
Public Property Get Printers() As Object
Set Printers = VB.Printers
End Property
Lediglich zwei Methoden bereiten Probleme. Die eine, wie bereits gesagt, ist die Print-Methode. Die Schwierigkeiten damit rühren wahrscheinlich daher, dass diese gar keine Methode im eigentlichen Sinne ist. Schon der VB-Objektkatalog verschweigt deren Existenz. Die Print-Methode, richtiger gesagt, die Print-Anweisung, ist ein Relikt aus der Basic-Historie. Mit ihrer eigenwillig anmutenden Syntax wissen moderne Script-Sprachen-Konzepte nichts mehr anzufangen. Eine Code-Zeile mit einem abschließenden Komma oder Semikolon ist hier ein Unding - für routinierte Print-Verwender dagegen das Selbstverständlichste von der Welt. Für den Fall, dass Sie diese spezielle Syntax nicht kennen sollten: Ein Komma gibt an, dass das nächste zu druckende Element an der nächsten (eingebauten) Tabulatorstelle ausgegeben wird, ein Semikolon gibt an, dass es unmittelbar und lückenlos auf das vorhergehende Element folgend ausgegeben wird. Kommata und Semikola können sowohl zwischen den zu druckenden Elementen als auch am Zeilenende stehen. Stehen sie am Zeilenende, wird damit signalisiert, dass die nächste Print-Anweisung an dieser Stelle dem Zeichen entsprechend weitermachen soll.
Die Code-Zeile
Print "ABC"; "DEF"; "GHI", "123"
sähe im Ausdruck etwa so aus:
ABCDEFGHI 123
Und die Anweisungsfolge
Print "Erste Zeile"
Print "Zweite Zeile",
Print "Immer noch zweite Zeile"
ergäbe:
Erste Zeile
Zweite Zeile Immer noch zweite Zeile
Schließlich resultiert aus den folgenden Anweisungen
Print "A";
Print "B";
Print "C"
im Druck:
ABC
Der Printer-Server muss daher selbst eine in etwa funktional gleichwertige Anweisung zur Verfügung stellen. Auf ein zu druckendes Element je Print-Aufruf reduziert, ist die Umsetzung recht einfach: Übergabe des zu druckenden Textelements im ersten Parameter, und in einem zweiten Parameter erfolgt die Übergabe einer Kennung, die quasi ein Komma oder ein Semikolon signalisiert, oder keines von beiden. Da Print in Basic ein strikt reserviertes Schlüsselwort ist, nennen wir die Ersatzmethode PrintText. Die Print-gemäße Gewohnheit, mehrere Elemente in einer Anweisungszeile übergeben zu können, müssen Sie jedoch ablegen - PrintText ist für jedes Element separat aufzurufen. Die Funktionalität ist jedoch entsprechend der übergebenen Kennung gewährleistet.
Public Sub PrintText(Text As Variant, Optional LineMode _
As Variant)
On Error Resume Next
If IsMissing(LineMode) Then
VB.Printer.Print Text
Else
Select Case CInt(LineMode)
Case 0
VB.Printer.Print Text
Case 1
VB.Printer.Print Text;
Case 2
VB.Printer.Print Text,
End Select
End If
If Err.Number Then
Err.Raise Err.Number, Err.Source, Err.Description, _
Err.HelpFile, Err.HelpContext
End If
End Sub
Die zweite angesprochene Schwierigkeit, die die Bild-Objekte betrifft, kommt bei der PaintPicture-Methode zum Tragen. Diese Methode würde als COM-konforme Methode klaglos funktionieren, wenn nicht die Scripting-Umgebung Probleme mit dem StdPicture-Objekt hätte. Ein solches Objekt kann offensichtlich nicht die Grenze zwischen dem VB-ActiveX-Server und der Scripting-Umgebung überschreiten - es tritt unweigerlich ein Automatisierungsfehler auf.
Wegen der vielen optionalen Parameter der PaintPicture-Methode, die jedoch beim Printer-Objekt keine leeren Variants annehmen können, ist die Umsetzung nicht mit einem simplen Durchreiche-Aufruf erledigt. Es muss vielmehr bei jedem einzelnen optionalen Parameter geprüft werden, ob ein Wert übergeben wurde. Entweder wird dieser oder, falls er fehlen sollte, ausdrücklich der Standardwert an den eigentlichen PaintPicture-Aufruf des VB-Print-Objekts übergeben. Da Scripting-Gepflogenheiten gemäß die übergebenen optionalen Parameter vom Datentyp Variant sind, kann die Übergabe eines Wertes leicht mit der VB-Funktion IsMissing geprüft werden.
Public Sub PaintPicture(Picture As Variant, Left1 As Variant, _
Top1 As Variant, Optional Width1 As Variant, Optional Height1 _
As Variant, Optional Left2 As Variant, Optional Top2 As Variant, _
Optional Width2 As Variant, Optional Height2 As Variant, _
Optional Opcode As Variant)
Dim nWidth1 As Single
Dim nHeight1 As Single
Dim nLeft2 As Single
Dim nTop2 As Single
Dim nWidth2 As Single
Dim nHeight2 As Single
Dim nOpcode As Long
Dim nPicture As StdPicture
On Error GoTo PaintPicture_Error
Set nPicture = Picture.Picture
With VB.Printer
If IsMissing(Width1) Then
nWidth1 = .ScaleX(nPicture.Width, vbHimetric, .ScaleMode)
Else
nWidth1 = CSng(Width1)
End If
If IsMissing(Height1) Then
nHeight1 = .ScaleX(nPicture.Height, vbHimetric, .ScaleMode)
Else
nHeight1 = CSng(Height1)
End If
If IsMissing(Left2) Then
nLeft2 = 0
Else
nLeft2 = CSng(Left2)
End If
If IsMissing(Top2) Then
nTop2 = 0
Else
nTop2 = CSng(Top2)
End If
If IsMissing(Width2) Then
nWidth2 = .ScaleX(nPicture.Width, vbHimetric, .ScaleMode)
Else
nWidth2 = CSng(Width2)
End If
If IsMissing(Height2) Then
nHeight2 = .ScaleX(nPicture.Width, vbHimetric, .ScaleMode)
Else
nHeight2 = CSng(Height2)
End If
If IsMissing(Opcode) Then
nOpcode = vbSrcCopy
Else
nOpcode = CLng(Opcode)
End If
.PaintPicture nPicture, CSng(Left1), CSng(Top1), nWidth1, _
nHeight1, nLeft2, nTop2, nWidth2, nHeight2, nOpcode
End With
Exit Sub
PaintPicture_Error:
Err.Raise Err.Number, Err.Source, Err.Description, _
Err.HelpFile, Err.HelpContext
End Sub
Sie sehen, dass auch hier von außen ein Picture-Objekt als Parameter übergeben werden soll. Doch wie verträgt sich dies meiner Aussage, dass das doch gar nicht ginge? Es verträgt sich, denn hier wird nicht das VB-bekannte, hier problematische StdPicture-Objekt übergeben, sondern ein eigenes, extra in diesem ActiveX-Server implementiertes Picture-Objekt - die Klasse avbPicture.
Deren Aufgabe ist ebenfalls nicht allzu umfangreich. Sie bildet die drei für Scripting-Zwecke wichtigen Eigenschaften des intern in der Objektvariablen mPicture verwalteten Originals eins zu eins ab - Height, Width und Type. Da Type wieder ein VB-Schlüsselwort ist, wird die Eigenschaft hier in PicType umbenannt. Beachten sie, dass die Eigenschaften Height und Width Werte in der Maßeinheit Himetric zurückgeben, während die Standardeinstellung des Printer-Objekts TWIPS ist. Die Umrechnung können Sie jedoch auf einfache Weise die ScaleX- bzw. ScaleY-Methode des Printer-Objekts vornehmen lassen. Eine Instanz dieser avbPicture-Klasse muss im Script mit CreateObject angelegt werden und kann nun ohne Fehlerauslösung an die PaintPicture-Methode des ActiveX-Servers übergeben werden, wo das eigentliche StdPicture-Objekt weitergereicht wird.
Private mPicture As Picture
Public Property Get Height() As Variant
Height = mPicture.Height
End Property
Public Property Get PicType() As Variant
PicType = mPicture.Type
End Property
Public Property Get Width() As Variant
Width = mPicture.Width
End Property
Public Property Get Picture() As Object
Set Picture = mPicture
End Property
Da ein leeres Picture-Objekt wertlos ist und VBScript bzw. der Scripting-Host nicht über die in VB vorhandenen Anweisungen LoadPicture und SavePicture verfügen, können Sie über die Methode LoadFromFile eine Bild- oder Grafik-Datei hineinladen. Mögliche Dateiformate sind: BMP, JPG, GIF, ICO, CUR und WMF. Wenn Sie wollen, können Sie eine geladene Bilddatei über die Methode SaveToFile unter dem gleichen oder unter einem neuen Dateinamen speichern. Eine Konvertierung des Bildformats kann das dahinterstehende StdPicture-Objekt jedoch nicht vornehmen - Sie sollten also die entsprechende Dateierweiterung in jedem Falle beibehalten.
Public Sub LoadFromFile(FileName As String)
On Error Resume Next
Set mPicture = LoadPicture(FileName)
If Err.Number Then
Err.Raise Err.Number, Err.Source, Err.Description, _
Err.HelpFile, Err.HelpContext
End If
End Sub
Public Sub SaveToFile(FileName As String)
On Error Resume Next
SavePicture mPicture, FileName
If Err.Number Then
Err.Raise Err.Number, Err.Source, Err.Description, _
Err.HelpFile, Err.HelpContext
End If
End Sub
Im Windows Scripting Host sähe die Verwendung der beiden Objekte etwa so aus:
Dim PrinterObj
Dim Printer
Dim Picture
Set PrinterObj = CreateObject("avbScriptPrinter.PrinterObj")
Set Printer = PrinterObj.Printer
Set Picture = CreateObject("avbScriptPrinter.avbPicture")
Picture.LoadFromFile "c:\windows\hlpbell.gif"
With Printer
.ScaleMode = 7
.CurrentX = 5
.CurrentY = 10
PrinterObj.PrintText "Hallo!"
.CurrentX = 5
PrinterObj.PrintText "Ist da jemand?"
PrinterObj.PaintPicture Picture, 7, 15
.EndDoc
End With
Wie Sie mit dem nun zur Verfügung stehenden, bei Visual Basic ausgeliehenen Printer-Objekt in Ihren Scripten umgehen, ist ein Thema für sich. In Anbetracht der sich auftuenden Möglichkeiten, aber auch der sich auftuenden Fallgruben, könnte man ganze Bücher darüber schreiben. Sie finden jedoch in nahezu jedem VB-Programmierbuch mehr oder weniger umfangreiche Kapitel zu diesem Thema. Die Methoden und Eigenschaften des VB-Printerobjekts finden Sie in der VB-Dokumentation beschrieben - entweder auf Ihren mit VB oder VS gelieferten MSDN-CDs oder in der Online-MSDN-Library (leider nur englischsprachig).
|