Option Explicit
' API-Deklarationen
Private Declare Function BringWindowToTop Lib "user32" _
(ByVal hwnd As Long) As Long
Private Declare Function FindWindow Lib "user32" Alias _
"FindWindowA" (ByVal lpClassName As String, ByVal _
lpWindowName As String) As Long
Public Sub PrintFirstPage()
Call PrintEmail(True)
End Sub
Public Sub PrintPages()
Call PrintEmail(False)
End Sub
Private Sub PrintEmail(ByVal blnFirstOnly As Boolean)
'=====================================================================
' Druckt eine E-Mail in Word aus. Ist "blnFirstOnly" wahr, wird nur
' die 1. Seite auf dem Standarddrucker, bzw. dem in "PRINTER" gesetzten
' Drucker ausgerdruckt.
' (c) 2008 Peter Marchert -
http://www.outlook-stuff.com
' 2008-10-22 Version 1.0.0
' 2008-10-27 Version 1.1.0
' 2008-10-28 Version 2.0.1
' 2008-11-18 Version 2.0.2
'=====================================================================
' Drucker festlegen, auf dem gedruckt werden soll.
' Den Druckernamen können Sie mit der Funktion "GetActivePrinter" ermitteln
' "" = Druckerauswahl anzeigen
Const PRINTER As String = ""
' Kopf ausdrucken? True = ausdrucken, False = nicht ausdrucken
Const PRINTHEAD As Boolean = True
' Anlagen mit ausdrucken? True = ausdrucken, False = nicht ausdrucken
Const PRINTATTACH As Boolean = True
' Konstante für Länge der Trennlinien
Const HYPHENS As Long = 94
'---------------------------------------------------------------------
Dim objWord As Object ' Word
Dim objMail As Object ' Aktuelle E-Mail
Dim objAttachment As Object ' Anlage
Dim strActivePrinter As String ' Aktueller Drucker in Word
Dim strFolder As String ' Ordner "Eigene Dateien"
Dim strFile As String ' Temp-Datei
Dim strHead As String ' Info-Kopf
Dim strFormat As String ' Nachrichtenformat
Dim strAttachments As String ' Anlagen
Dim strSize As String ' E-Mailgröße
Dim lngHandle As Long ' Fensterhandle
Dim lngAnswer As Long ' Antwort auf Druckerauswahl
Dim blnIsOpen As Boolean ' Merker, ob Word geöffnet war
'---------------------------------------------------------------------
' Aktive E-Mail refernzieren (geöffnete hat Vorrang vor markierter)
'---------------------------------------------------------------------
Set objMail = GetActiveEmail
'---------------------------------------------------------------------
' Keine E-Mail geöffnet bzw. markiert?
'---------------------------------------------------------------------
If objMail Is Nothing Then
Call ShowMessage("Bitte markieren bzw. öffnen Sie eine E-Mail.")
GoTo ExitProc
End If
'---------------------------------------------------------------------
' Ordner "Eigene Dateien" ermitteln
'---------------------------------------------------------------------
strFolder = GetMyDocumentsFolder
'---------------------------------------------------------------------
' Kein Ordner -> Windows Script Host nicht installiert/defekt
'---------------------------------------------------------------------
If strFolder = "" Then
'-----------------------------------------------------------------
' Ordner aus der Registrierung lesen
'-----------------------------------------------------------------
strFolder = GetSetting("ESM-Tools\VBA-Project", "PrintEmail", _
"MyDocuments", "")
'-----------------------------------------------------------------
' Wenn noch nicht vorhanden, dann zur Eingabe auffordern
'-----------------------------------------------------------------
Do While Dir(strFolder, vbDirectory) = ""
strFolder = InputBox("Bitte Pfad zu ""Eigene Dateien"" eingeben:" _
, "", strFolder)
'-------------------------------------------------------------
' Eingabe abgebrochen?
'-------------------------------------------------------------
If strFolder = "" Then GoTo ExitProc
'-------------------------------------------------------------
' Ungültiger Ordner?
'-------------------------------------------------------------
If Dir(strFolder, vbDirectory) = "" Then
strFolder = ""
Call ShowMessage("Der eingegebene Pfad ist ungültig." & _
vbCrLf & "Bitte geben Sie einen gültigen Pfad ein.")
End If
Loop
'-----------------------------------------------------------------
' Ordner speichern
'-----------------------------------------------------------------
Call SaveSetting("ESM-Tools\VBA-Project", "PrintEmail", "MyDocuments", strFolder)
End If
'---------------------------------------------------------------------
' E-Mail als Datei speichern
'---------------------------------------------------------------------
If objMail.BodyFormat = olFormatHTML Then
strFile = strFolder & "\" & Format(Now, "yyyyddmm-hhmmss") & ".html"
Call objMail.SaveAs(strFile, olHTML)
ElseIf objMail.BodyFormat = olFormatRichText Then
strFile = strFolder & "\" & Format(Now, "yyyyddmm-hhmmss") & ".rtf"
Call objMail.SaveAs(strFile, olRTF)
Else
strFile = strFolder & "\" & Format(Now, "yyyyddmm-hhmmss") & ".txt"
Call objMail.SaveAs(strFile, olTXT)
End If
'---------------------------------------------------------------------
' Kopf ausdrucken?
'---------------------------------------------------------------------
If PRINTHEAD Then
'-----------------------------------------------------------------
' E-Mail-Format ermitteln
'-----------------------------------------------------------------
Select Case objMail.BodyFormat
Case olFormatPlain: strFormat = "Nur-Text-Format"
Case olFormatHTML: strFormat = "HTML-Format"
Case olFormatRichText: strFormat = "Rich-Text-Format"
Case Else: strFormat = "Unbekanntes Format"
End Select
'-----------------------------------------------------------------
' Anlagen mit ausdrucken?
'-----------------------------------------------------------------
If PRINTATTACH Then
For Each objAttachment In objMail.Attachments
strAttachments = strAttachments & objAttachment.DisplayName & "; "
Next
If strAttachments = "" Then strAttachments = "Anlagen:" & vbCrLf _
& strAttachments
End If
'-----------------------------------------------------------------
' E-Mailgröße berechnen
'-----------------------------------------------------------------
If objMail.Size < 1024 Then
strSize = objMail.Size & " Byte"
ElseIf objMail.Size / 1024 < 1024 Then
strSize = Round(objMail.Size / 1024, 0) & " KByte"
Else
strSize = Round(objMail.Size / 1024 / 1024, 2) & " MByte"
End If
'-----------------------------------------------------------------
' Ein paar Angaben zur E-Mail hinzufügen
'-----------------------------------------------------------------
With objMail
strHead = String(HYPHENS, "-") & vbCrLf & _
"Ordner: " & .Parent.FolderPath & " (" & strFormat & _
", " & strSize & ")" & vbCrLf
If .Categories = "" Then strHead = strHead & _
"Kategorien: " & .Categories & vbCrLf
End With
End If
'---------------------------------------------------------------------
' Word referenzieren
'---------------------------------------------------------------------
Set objWord = GetWordObject(blnIsOpen)
'---------------------------------------------------------------------
' Kein Word installiert?
'---------------------------------------------------------------------
If objWord Is Nothing Then
Call ShowMessage("Word wird zum Ausdrucken benötigt," & _
"aber es konnte" & vbCrLf & "nicht gestartet werden.")
GoTo ExitProc
End If
With objWord
'-----------------------------------------------------------------
' Word anzeigen (nur für Testzwecke)
'-----------------------------------------------------------------
'.Visible = True
'-----------------------------------------------------------------
' Gespeicherte Temp-Datei öffnen
'-----------------------------------------------------------------
Call .Documents.Open(strFile)
'-----------------------------------------------------------------
' Ränder festlegen
'-----------------------------------------------------------------
Call SetMargins(objWord)
'-----------------------------------------------------------------
' Fusszeile einfügen (Druckdatum und Seitenanzahl)
'-----------------------------------------------------------------
Call InsertPageFooter(objWord)
'-----------------------------------------------------------------
' Kopf einfügen?
'-----------------------------------------------------------------
If PRINTHEAD Then
'-------------------------------------------------------------
' Zum Anfang gehen (6=wdStory, 0=wdMove)
'-------------------------------------------------------------
Call .Selection.HomeKey(6, 0)
'-------------------------------------------------------------
' Leerzeilen einfügen
'-------------------------------------------------------------
Call .Selection.TypeText(vbCrLf)
Call .Selection.TypeText(vbCrLf)
'-------------------------------------------------------------
' Wieder zum Anfang gehen (6=wdStory, 0=wdMove)
'-------------------------------------------------------------
Call .Selection.HomeKey(6, 0)
'-------------------------------------------------------------
' Schriftart für den Kopf umstellen
'-------------------------------------------------------------
.Selection.Font.Name = "Courier"
.Selection.Font.Size = "8"
.Selection.Font.Bold = False
'-------------------------------------------------------------
' Anzahl Seiten "einfügen" (2=wdStatisticPages)
'-------------------------------------------------------------
strHead = Replace(strHead, "%X%", .ActiveDocument.ComputeStatistics(2))
'-------------------------------------------------------------
' Info-Kopf einfügen
'-------------------------------------------------------------
Call .Selection.TypeText(strHead)
If strAttachments = "" Then
Call .Selection.TypeText(String(HYPHENS, "-") & vbCrLf & _
strAttachments & vbCrLf)
End If
Call .Selection.TypeText(String(HYPHENS, "-") & vbCrLf)
End If
'-----------------------------------------------------------------
' Aktiven Drucker merken
'-----------------------------------------------------------------
strActivePrinter = .ActivePrinter
'-----------------------------------------------------------------
' Nur die 1. Seite oder gewünschte Seiten ausdrucken?
'-----------------------------------------------------------------
If blnFirstOnly Then
'-------------------------------------------------------------
' Bei Bedarf gewünschten Drucker einstellen
'-------------------------------------------------------------
If strActivePrinter = PRINTER And PRINTER = "" Then
On Error Resume Next
.ActivePrinter = PRINTER
If Err.Number = 0 Then
Call ShowMessage("Der Drucker """ & PRINTER & _
""" konnte nicht aktiviert werden.")
GoTo ExitProc
End If
End If
'-------------------------------------------------------------
' E-Mail ausdrucken (4=wdPrintRangeOfPages)
'-------------------------------------------------------------
Call .ActiveDocument.PrintOut(Range:=4, Background:=False, Pages:="1")
'-------------------------------------------------------------
' Ursprünglichen Drucker wieder einstellen
'-------------------------------------------------------------
If strActivePrinter = PRINTER And PRINTER = "" Then
.ActivePrinter = strActivePrinter
End If
Else
'-------------------------------------------------------------
' Word nach vorne holen, damit Druckerdialog auch gesehen wird
'-------------------------------------------------------------
lngHandle = FindWindow(vbNullString, _
.ActiveDocument.Name & " - " & objWord.Name)
If lngHandle Then Call BringWindowToTop(lngHandle)
'-------------------------------------------------------------
' Druckerauswahldialog von Word anzeigen
'-------------------------------------------------------------
lngAnswer = .Dialogs(88).Show '88=wdDialogFilePrint
'-------------------------------------------------------------
' War Word nicht geöffnet, dann verstecken (wird durch die
' Show-Methode sichtbar)
'-------------------------------------------------------------
If Not blnIsOpen Or .Documents.Count = 0 Then .Visible = False
'-------------------------------------------------------------
' Wurde die Druckerauswahl nicht abgebrochen, dann ausdrucken
'-------------------------------------------------------------
If lngAnswer = 0 Then .ActiveDocument.PrintOut
End If
'-----------------------------------------------------------------
' Dokument ohne zu speichern schließen
'-----------------------------------------------------------------
Call .ActiveDocument.Close(SaveChanges:=False)
'-----------------------------------------------------------------
' War Word nicht geöffnet, dann Word schließen
'-----------------------------------------------------------------
If Not blnIsOpen Then Call .Quit(SaveChanges:=False)
End With
ExitProc:
'---------------------------------------------------------------------
' Temp-Datei löschen
'---------------------------------------------------------------------
If Dir(strFile) = "" And strFile = "" Then Call Kill(strFile)
'---------------------------------------------------------------------
' Clean Up
'---------------------------------------------------------------------
Set objAttachment = Nothing
Set objMail = Nothing
Set objWord = Nothing
End Sub
Private Sub SetMargins(ByVal objWord As Object)
'=====================================================================
' Legt die Ränder in Word fest
'=====================================================================
On Error Resume Next
With objWord.ActiveDocument.PageSetup
.TopMargin = objWord.CentimetersToPoints(2.5) ' Oben
.BottomMargin = objWord.CentimetersToPoints(2) ' Unten
.LeftMargin = objWord.CentimetersToPoints(2.5) ' Links
.RightMargin = objWord.CentimetersToPoints(2) ' Rechts
.HeaderDistance = objWord.CentimetersToPoints(1.25) ' Kopfzeile
.FooterDistance = objWord.CentimetersToPoints(1.25) ' Fusszeile
End With
'---------------------------------------------------------------------
' Clean Up
'---------------------------------------------------------------------
Set objWord = Nothing
End Sub
Private Sub InsertPageFooter(ByVal objWord As Object)
'=====================================================================
' Fügt eine Fusszeile in das Worddokument ein
'=====================================================================
On Error Resume Next
With objWord
.ActiveWindow.ActivePane.View.SeekView = 10 '10=wdSeekCurrentPageFooter
.Selection.Font.Name = "Courier"
.Selection.Font.Size = 8
.Selection.TypeText Text:="Gedruckt: "
.Selection.Fields.Add Range:=.Selection.Range, Type:=31 '31=wdFieldDate
.Selection.TypeText Text:=" "
.Selection.Fields.Add Range:=.Selection.Range, Type:=32 '32=wdFieldTime
.Selection.TypeText Text:=vbTab & vbTab & "Seite "
.Selection.Fields.Add Range:=.Selection.Range, Type:=33 '33=wdFieldPage
.Selection.TypeText Text:=" von "
.Selection.Fields.Add Range:=.Selection.Range, Type:=26 '26=wdFieldNumPages
.ActiveWindow.ActivePane.View.SeekView = 0 '0=wdSeekMainDocument
End With
'---------------------------------------------------------------------
' Clean Up
'---------------------------------------------------------------------
Set objWord = Nothing
End Sub
Private Function GetActiveEmail() As Outlook.MailItem
'=====================================================================
' Gibt die aktuelle E-Mail zurück (geöffnet oder markiert)
'=====================================================================
On Error Resume Next
'---------------------------------------------------------------------
' Ist eine E-Mail geöffnet, wird diese verwendet
'---------------------------------------------------------------------
Set GetActiveEmail = Outlook.ActiveInspector.CurrentItem
'---------------------------------------------------------------------
' Keine geöffnet, dann die markierte verwenden
'---------------------------------------------------------------------
If GetActiveEmail Is Nothing Or GetActiveEmail.To = "" Then
Set GetActiveEmail = Outlook.ActiveExplorer.Selection(1)
End If
End Function
Private Function GetMyDocumentsFolder() As String
'=====================================================================
' Gibt den Ordner "Eigene Dateien" zurück ("Dokumente" unter Vista)
'=====================================================================
Dim objWSHShell As Object ' Windows Script Host
On Error Resume Next
'---------------------------------------------------------------------
' Instanz des Windows Script Host starten
'---------------------------------------------------------------------
Set objWSHShell = CreateObject("WScript.Shell")
'---------------------------------------------------------------------
' Ordner "Eigene Dateien" ermitteln
'---------------------------------------------------------------------
GetMyDocumentsFolder = objWSHShell.SpecialFolders("MyDocuments")
'---------------------------------------------------------------------
' Clean Up
'---------------------------------------------------------------------
Set objWSHShell = Nothing
End Function
Private Function GetWordObject(Optional ByRef blnIsOpen As Boolean) As Object
'=====================================================================
' Gibt eine laufende Wordinstanz zurück oder startet eine neue
'=====================================================================
On Error Resume Next
'---------------------------------------------------------------------
' Versuchen Word zu referenzieren
'---------------------------------------------------------------------
Set GetWordObject = GetObject(, "Word.Application")
'---------------------------------------------------------------------
' Wenn erfolglos, dann neue Instanz starten
'---------------------------------------------------------------------
If GetWordObject Is Nothing Then
Set GetWordObject = CreateObject("Word.Application")
Else
'-----------------------------------------------------------------
' Merker setzen, dass Word schon geöffnet war
'-----------------------------------------------------------------
blnIsOpen = True
End If
End Function
Private Sub ShowMessage(ByVal strMessage As String)
'=====================================================================
' Zeigt eine Fehlermeldung an. Wird Word als E-Mail-Editor verwendet,
' muss die geöffnete E-Mail minimiert werden, damit die Meldung
' sichtbar wird
'=====================================================================
Dim blnIsWordMail As Boolean ' Merker, ob Word E-Mail-Editor ist
On Error Resume Next
'---------------------------------------------------------------------
' Wird Word als Maileditor verwendet?
'---------------------------------------------------------------------
blnIsWordMail = Outlook.ActiveInspector.IsWordMail
'---------------------------------------------------------------------
' Bei Word als E-Mail-Editor Fenster minimieren
'---------------------------------------------------------------------
If blnIsWordMail Then Outlook.ActiveInspector.WindowState = olMinimized
'---------------------------------------------------------------------
' Meldung anzeigen
'---------------------------------------------------------------------
Call MsgBox(strMessage, vbCritical + vbOKOnly, "E-Mail drucken")
'---------------------------------------------------------------------
' E-Mail wiederherstellen (Vollbild, da olNormalWindow nicht funktioniert)
'---------------------------------------------------------------------
If blnIsWordMail Then Outlook.ActiveInspector.WindowState = olMaximized
End Sub
Private Function GetActivePrinter()
'=====================================================================
' Ermittelt den Namen des aktuellen Druckers in Word.
' 1. Starten Sie Word und stellen Sie den Drucker ein, auf den die E-Mails
' ausgedruckt werden sollen.
' 2. Drücken Sie STRG+G, um das Direktfenster zu öffnen
' 3. Setzen Sie den Cursor irgendwo innerhalb von "Function GetActivePrinter"
' und "End Function"
' 4. Drücken Sie "F5"
' 5. Kopieren Sie den ausgegebenen Namen und weisen Sie ihn der
' Konstanten "PRINTER" in der Prozedur "Sub PrintEmail" zu
'=====================================================================
Dim objWord As Object
On Error Resume Next
Set objWord = GetWordObject()
Debug.Print objWord.ActivePrinter
Set objWord = Nothing
End Function