mesaou
Goto Top

Reagieren auf das Schließen des Adobe Reader Druckfensters

Ich hatte vor kurzem das Problem mit dem AxAcroPDF-Steuerelement aus VS2013 Express zu drucken, dank eurer Hilfe konnte ich das Problem lösen. Jetzt stehe ich vor einem Folgeproblem und zwar möchte ich, dass nach dem Druck von einem oder mehereren Druckern (jeweils über das Druckfenster vom Adobe Reader) das Dokument noch in einem "Archiv-Ordner" abgelegt wird. Das Problem ist, dass ich im Moment entweder eine Messagebox einbauen muss und dann mit dem nächsten Druck warte bis die Messagebox mit OK beendet wurde oder den kompletten Druckvorgang einfach überspringe und die PDF-Datei einfach direkt verschiebe. Ich würde gerne auf das Schließen des Druckfensters vom Adobe Reader reagieren habe aber leider weder hier noch im restlichen Netz was genaueres dazu gefunden. Ich habe mir auch den Taskmanager schonmal angeschaut nur taucht da leider nichts gesondertes auf, während das Druckfenster offen ist. Die AcroRd32.exe ist vorher schon offen da ich in meinem Programm, aus dem heraus ich drucke, das AxAcroPDF-Steuerelement verwende. Könnte mir bitte jemand das Brett vorm Kopf wegnehmen?

Grüße
Mesaou

Content-Key: 261416

Url: https://administrator.de/contentid/261416

Printed on: April 19, 2024 at 12:04 o'clock

Mitglied: 114757
114757 Jan 28, 2015 at 15:11:56 (UTC)
Goto Top
Member: Mesaou
Mesaou Jan 29, 2015 at 10:10:13 (UTC)
Goto Top
So hab mir gestern den Link noch angeschaut und heute noch weiter mit überlegt. Ich glaube aber dass er mein Problem nicht ganz abdeckt. Vielleicht habe ich mein Problem nicht genau genug beschrieben.
Der Ablauf ist folgendermaßen:

- Es wird mit einem PDF-Drucker ein PDF erstellt und in einem bestimmten Ordner abgelegt
- Sobald in dem bestimmten Ordner eine PDF-Datei erzeugt wird springt mein Programm an, lädt die Datei in das AxAcroPDF-Steuerelement und zeigt alle Drucker die auf dem System installiert sind an (diese kann man mittels einer Checkbox anwählen)
- Nun hat der User zwei Möglichkeiten zum drucken:

- Direktdruck:
Dokument wird von alle gewählten Druckern in der gewünschten Anzahl aus und verschiebt die Datei in den "Archiv-Ordner" sofern die entsprechende Checkbox gesetzt ist, ansonsten wird das Dokument gelöscht. Diese Funktion funktioniert bereits.

- Druck mit Einstellungen:
Es wird das Druckfenster des AdobeReaders angezeigt (und nur dieses es wird also kein AdobeReader Fenster geöffnet) aktuell wird auch noch eine Messagebox geöffnet. Sobald diese geschlossen wird geht das Programm zum nächsten ausgewählten Drucker und öffnet für diesen das Druckfenster. Dieser Vorgang wird wiederholt bis alle gewählten Drucker angezeigt wurden. Als letztes wird das Dokument ins Archiv verschoben sofern die Checkbox gesetzt ist, ansonsten wird das Dokument gelöscht. Die Messagebox wird benötigt, weil das Programm ansonsten nicht auf das Beenden der Druckaufträge/fenster wartet und direkt bis zum Archivieren/Löschen weiter geht. Danach wird der streamtoprint geschlossen und damit auch das Druckfenster (weitere Druckfenster werden erst garnicht geöffnet). Ich würde jetzt gerne diese Messagebox umgehen und stattdessen den nächsten Druck automatisch anstoßen sobald der letzte Druck fertig ist bzw eine bestimmte Zeit nachdem das Druckfenster geschlossen wurde. die AxAcroPDF.Print()-Methode ist leider zum einen Void und ist sofort beendet auch wenn der Druck noch nicht abgeschlossen ist (Adobe Documentation: This method returns immediately, even if the printing has not completed.)
Mitglied: 114757
Solution 114757 Jan 29, 2015 updated at 13:04:15 (UTC)
Goto Top
Dann bleibt dir noch die Druckerwarteschlange des Druckers zu überwachen (z.B. via WMI) ...
Member: Mesaou
Mesaou Jan 29, 2015 updated at 14:38:56 (UTC)
Goto Top
Danke für den Tipp, jetzt funktionierts. Hab im Netz ne einfache Möglichkeit zum auslesen der Druckerwarteschleife gefunden (http://www.vbarchiv.net/tipps/tipp_1915-druckerwarteschlange-auslesen.h ..) und lese jetzt zum einen die Warteschlange aus und warte an der Stelle der Messagebox noch 20 Sekunden (ich weiß nicht warum das vorher mit nur warten nicht funktioniert hat ... vielleicht hab ich da nen falschen Befehl benutzt) sobald mindestens 20 Sekunden vergangen sind und die Warteschlange leer ist gehe ich zum nächsten Drucker bzw zum Archiv. Bin gerade noch auf einen kleinen Schönheitsfehler gestoßen, und zwar würde ich gerne sofort zum nächsten Drucker gehen sobald etwas mit dem gerade gewählten Drucker gedruckt wurde. Mein derzeitiger Ansatz funktioniert aber leider nicht. Das Programm wartet die komplette Wartezeit und geht erst dann zum nächsten Drucker/Archiv auch wenn in der Zwischenzeit etwas gedruckt wurde.

Alle Checkboxen bis auf die Archiv-Checkbox enthalten Drucker. Die Zeilen 20 - 31 enthalten die Schleife, die bis zum nächsten Druck durchlaufen werden soll.

For Each Ctrl In Me.Controls
            If TypeOf Ctrl Is CheckBox Then
                If Not DirectCast(Ctrl, CheckBox).Name = "chkbArchiv" Then  
                    If DirectCast(Ctrl, CheckBox).Checked Then
                        Try
                            streamToPrint = New StreamReader(filePath)
                            Try
                                AddHandler PrintDocument1.PrintPage, AddressOf PrintDocument1_PrintPage
                                PrintDocument1.PrinterSettings.PrinterName = DirectCast(Ctrl, CheckBox).Text
                                Shell(String.Format("rundll32 printui.dll,PrintUIEntry /y /n ""{0}""", DirectCast(Ctrl, CheckBox).Text))  
                                AxAcroPDF1.Print()
                            Finally
                                streamToPrint.Close()
                            End Try
                        Catch ex As Exception
                            MessageBox.Show(ex.Message)
                        End Try
                        Wartezeitende = Date.Now.Hour * 3600 + Date.Now.Minute * 60 + Date.Now.Second + 20

                        Dim Counter As Integer = 0
                        Do While True
                            If Not Warteschlangeleer(DirectCast(Ctrl, CheckBox).Text) Then
                                Counter = 1
                            End If
                            If Warteschlangeleer(DirectCast(Ctrl, CheckBox).Text) And Counter = 1 Then
                                Counter = 2
                            End If
                            If (Warteschlangeleer(DirectCast(Ctrl, CheckBox).Text) And Date.Now.Hour * 3600 + Date.Now.Minute * 60 + Date.Now.Second > Wartezeitende) Or (Counter = 2) Then
                                Exit Do
                            End If
                        Loop
                    End If
                End If
            End If
        Next

Hilfsfunktionen aus dem oben geposteten Link (leicht geändert):
Private Function Warteschlangeleer(Druckername As String) As Boolean
        Dim JobQuery As String = "Select * From Win32_Printjob"  
        Warteschlangeleer = True
        Dim Printer As String = ""  
        Dim Jobs As New ManagementObjectSearcher(JobQuery)
        For Each Job As ManagementObject In Jobs.Get()
            Printer = WMIGetInfo(Job, "DriverName")  
            If Printer = Druckername Then
                Warteschlangeleer = False
            End If
        Next
    End Function
    Private Function WMIGetInfo(ByVal WMIObj As ManagementObject, _
    ByVal Key As String) As String

        If Not WMIObj(Key) Is Nothing Then
            Return WMIObj(Key).ToString
        Else
            Return ""  
        End If
    End Function
Member: Mesaou
Mesaou Jan 29, 2015 at 15:49:11 (UTC)
Goto Top
OK ... gerade noch was anderes getestet. Das Problem ist, dass der Drucker nicht so heißt wie sein Treiber, ich muss also nur noch herausfinden ob die WMI auch den echten Namen übergibt.
Mitglied: 114757
Solution 114757 Jan 29, 2015, updated at Jan 30, 2015 at 07:46:30 (UTC)
Goto Top
Zitat von @Mesaou:

OK ... gerade noch was anderes getestet. Das Problem ist, dass der Drucker nicht so heißt wie sein Treiber, ich muss also
nur noch herausfinden ob die WMI auch den echten Namen übergibt.
In der Eigenschaft Name des Printjobs steht der Druckername, musst du nur anhand des Kommas trennen
Printer = WMIGetInfo(Job, "Name").split(",")(0)  
oder für den Fall das der Druckername ein Komma enthalten sollte:
Printer = WMIGetInfo(Job, "Name")  
Printer = Printer.Substring(0,Printer.LastIndexOf(","))  
Member: Mesaou
Mesaou Jan 30, 2015 at 07:46:20 (UTC)
Goto Top
Danke für die Idee ich habs etwas anders gemacht. Hab mir erstmal alle WMI-Infos ausgeben lassen und dann gesehen dass Caption, Name und Description den selben Inhalt haben, Name wird das richtige sein da ich beim Suchen der Drucker auch nach dem Namen suche. Danach mache ich ein
If(Instr(Name, Druckername)>0)

Grüße
Mesaou
Member: Mesaou
Mesaou Jan 30, 2015, updated at Feb 02, 2015 at 15:25:09 (UTC)
Goto Top
Was wäre die Welt wenn man nicht immer noch was finden würde wo man dran rumschrauben könnte. Wie gesagt an sich funktioniert jetzt alles. Wenn man den Druckdialog aber vor Ablauf der Wartezeit abbricht, wird in diesem Moment keine der Bedingungen für das Verlassen der Schleife erfüllt (Es wurde nichts in die Warteschlange gegeben => Counter noch 0 und die Wartezeit ist noch nicht abgelaufen), damit muss man warten bis die Zeit abgelaufen ist. Ich suche gerade nach einer Möglichkeit in diesem Fall vorzeitig aus der Schleife zu gehen. Falls jemand ne Idee hat würde ich mich über eine Erleuchtung freuen.

Grüße
Mesaou

P.S.
Das Problem an dem ich hänge ist das die AxAcroPDF.Print() keinen Rückgabewert hat und diesen damit auch nicht mit prüfen kann. Meine Suche nach einem Workaround ist bisher leider erfolglos.
Member: Mesaou
Mesaou Feb 03, 2015 updated at 15:43:08 (UTC)
Goto Top
Ist es möglich mit VB.Net abzufangen, wenn sich ein Fenster öffnet (hier das Druckfenster) und dann eine ID oder was ähnliches zu ermitteln um damit in der Schleife zu prüfen ob das Fenster mit der ID noch offen ist? Habe leider noch keine Umsetzung dafür gefunden.
Member: Mesaou
Mesaou Feb 04, 2015 at 15:49:12 (UTC)
Goto Top
So ich hab jetzt ne Lösung, falls noch jemand auf dieses Problem stoßen sollte:

Die Abbruchbedingungen ist jetzt:
- Eine leere Warteschlange UND
- Das Acrobat-Steuerelement muss den Fokus bekommen haben UND
- Das Ablaufen einer 2-Sekunden-Wartezeit


Die erste Bedingung lässt sich über WMIGetInfo zu prüfen.
Die zweite Bedingung wird mit der AcroCheck-Variable (global, wird nur in der AxAcroPDF1_Enter gesetzt) kontrolliert.
Für die letzte Bedingung speichere ich mir die auf Sekunden heruntergebrochene Zeit in 2 Sekunden ab, sobald das Acrobat-Steuerelement den Fokus bekommt. Die Zeit wird erst hier gesetzt da der User prinzipiell zu einer beliebigen Zeit auf den Druck bzw Abbruchbutton klicken kann.
Bricht der User den Druckdialog ab sind alle bedingungen 2 Sekunden später erfüllt, da kein Dokument in die Warteschlange kommt.
Druckt der User bleibt man in der Warteschleife bis das Dokument fertig gedruckt ist (bzw falls es ein kleines Dokument ist auch mindestens 2 Sekunden)

If (Warteschlangeleer(DirectCast(Ctrl, CheckBox).Text, filePath) And AcroCheck And Date.Now.Hour * 3600 + Date.Now.Minute * 60 + Date.Now.Second > Wartezeitende2 ) Then
      Exit Do
End If
    Private Sub AxAcroPDF1_Enter(sender As Object, e As EventArgs) Handles AxAcroPDF1.Enter
        AcroCheck = True
        Wartezeitende2 = Date.Now.Hour * 3600 + Date.Now.Minute * 60 + Date.Now.Second + 2
    End Sub