Drucken aus vorher festgelegter Papierkassette

Anfängerfragen zum Programmieren mit PureBasic.
MK_2007
Beiträge: 11
Registriert: 05.02.2008 17:43

Drucken aus vorher festgelegter Papierkassette

Beitrag von MK_2007 »

Hallo zusammen,
ich habe hier im Forum schon viele Anregungen, Tips und Lösungen finden können. Dafür erst mal vielen Dank.
Nun wende ich mich mit einer Frage an Euch.
Ich habe einen Drucker (Canon iR2270) mit 4 Papierkassetten.
In jeder liegen unterschiedliche Kopfbögen. Nun möchte ich aus meinem Programm je nach Selektion eines Dokumentes, dass automatisch aus der richtigen Kassette gedruckt wird ohne das der Anwender sie einstellen muß.
Wir programmiere ich diesen Aufruf? Schon mal vielen Dank für Eure Hilfe.
re@l
Beiträge: 4
Registriert: 06.02.2008 13:04

Beitrag von re@l »

Ich denke mal, dass das relativ schwer wird, weil du ja den Drucker direkt mit Kommandos ansprechen müsstest.
Benutzeravatar
Fluid Byte
Beiträge: 3110
Registriert: 27.09.2006 22:06
Wohnort: Berlin, Mitte

Beitrag von Fluid Byte »

Geht soweit ich weiß nur über den Treiber. Mir ist keine Windows API-Funktion bekannt womit man die Ausgabefächer direkt ansprechen kann. Wird 'ne harte Nuss, ist aber eigentlich auch sinnlos. Wenn der Druckdialog kommt musst du lediglich auf "Optionen" (oder ähnlich) klicken und das Ausgabefach auswählen. Das sind zwei Klicks und gibt somit zu bedenken ob das den Aufwand wert ist. Zudem musst bei einem Wechsel des Druckermodels dich erneut durch die entsprechende API kämpfen.
Windows 10 Pro, 64-Bit / Outtakes | Derek
Benutzeravatar
Shardik
Beiträge: 746
Registriert: 25.01.2005 12:19

Beitrag von Shardik »

Fluid Byte hat geschrieben: Geht soweit ich weiß nur über den Treiber. Mir ist keine Windows API-Funktion bekannt womit man die Ausgabefächer direkt ansprechen kann.
Diese Aussage ist nicht korrekt. Gib einmal in der PureBASIC-IDE #DMB ein und Du siehst, daß dort 16 Einträge mit #DMBIN_xxx angezeigt werden. Dies sind allesamt vordefinierte Konstanten für die Papierschacht-Auswahl. Und TerryHough hat im englischen Forum ein Code-Beispiel veröffentlicht, in dem er neben Simplex/Duplex-Druck auch zwischen zumindest 2 Papiereinzugsschächten umschaltet:
http://www.purebasic.fr/english/viewtop ... 10&start=8
Benutzeravatar
Fluid Byte
Beiträge: 3110
Registriert: 27.09.2006 22:06
Wohnort: Berlin, Mitte

Beitrag von Fluid Byte »

Shardik hat geschrieben:Diese Aussage ist nicht korrekt.
Ruhig brauner, das hab ich auch nicht behauptet. Es war lediglich eine Annahme. Bild
Shardik hat geschrieben:Gib einmal in der PureBASIC-IDE #DMB ein und Du siehst, daß dort 16 Einträge mit #DMBIN_xxx angezeigt werden.
Dies sind allesamt vordefinierte Konstanten für die Papierschacht-Auswahl.
Das Problem ist das diese begrenzt sind. Wenn man 4, 5 oder sogar mehr Fächer hat wie z. B. bei einen Multidrucker (Drucker+Kopierer Combo) dann kommst du damit nicht weit. Ich muss nochmal genauer suchen aber ich glaube man kann die Anzahl der Fächer iregendwie ermitteln und den Wert dann bei dmDefaultSource der DEVMODE Struktur setzen.


This member can be one of the following values, or it can be a device-specific value greater than or equal to DMBIN_USE
Shardik hat geschrieben:Und TerryHough hat im englischen Forum ein Code-Beispiel veröffentlicht, in dem er neben Simplex/Duplex-Druck auch zwischen zumindest 2 Papiereinzugsschächten umschaltet:
http://www.purebasic.fr/english/viewtop ... 10&start=8
Ich habe zuhause keinen Drucker deshalb muss ich mal versuchen den Code morgen in der Firma zu testen.
Windows 10 Pro, 64-Bit / Outtakes | Derek
Benutzeravatar
Shardik
Beiträge: 746
Registriert: 25.01.2005 12:19

Beitrag von Shardik »

Fluid Byte hat geschrieben: Ich muss nochmal genauer suchen aber ich glaube man kann die Anzahl der Fächer iregendwie ermitteln
So geht es (Ermittlung der Anzahl Einzugfächer und ihrer Namen):

Code: Alles auswählen

EnableExplicit

#BinNameLength = 24

Define BinNameBuffer.S
Define Buffer.S
Define DefaultPrinterName.S
Define DefaultPortName.S
Define i.L
Define Info.S
Define NumBins.L
Define Result.L

BinNameBuffer = Space(20 * #BinNameLength) ; maximal 20 Papiereinzugfach-Namen passen hier hinein!
Buffer = Space(260)

; Default-Druckernamen und Drucker-Port ermitteln

GetPrivateProfileString_("WINDOWS", "DEVICE", "", @Buffer, 260, "Win.Ini")
DefaultPrinterName = StringField(Buffer, 1, ",")
DefaultPortName = StringField(Buffer, 3, ",")

; Namen der Fächer ermitteln

NumBins = DeviceCapabilities_(@DefaultPrinterName, @DefaultPortName, #DC_BINNAMES, @BinNameBuffer, 0)

Select NumBins
  Case -1
    Info = Info + #CR$ + "Der Aufruf der Windows-Funktion DeviceCapabilities() ist fehlgeschlagen!"
  Case 0
    Info = Info + #CR$ + "Der Abfrage der Papiereinzugfach-Namen wird vom Druckertreiber nicht unterstützt!"
  Default
    For i = 0 To NumBins - 1
      Info + #CR$ + Trim(PeekS(@BinNameBuffer + i * #BinNameLength))
    Next i
EndSelect

MessageRequester("Papiereinzugfach-Namen von " + DefaultPrinterName, Info, #MB_ICONINFORMATION)
OT
>Ruhig brauner

Für den, der diese Bemerkung nicht versteht, Wikipedia hilft: :wink:
http://en.wikipedia.org/wiki/Shardik
http://en.wikipedia.org/wiki/Shardik_%28bear%29

Allerdings ist Shardik schon nicht mehr braun, sondern fast weiß und sogar noch etwas älter als ts-soft :lol:
/OT
Benutzeravatar
Shardik
Beiträge: 746
Registriert: 25.01.2005 12:19

Beitrag von Shardik »

Hier ist ein (etwas komplizierteres) Komplett-Beispiel, das alle Papiereinzugsfächer des Default-Druckers zur Auswahl anbietet, aus dem ausgewählten Fach eine Seite einzieht und die Seite mit der Bezeichnung des Faches versehen ausdruckt:

Code: Alles auswählen

EnableExplicit

#BinNameLength = 24

Procedure.L ChangeBin(PrinterName.S, BinID.W)
  Protected BufferSize.L
  Protected BytesRetrieved.L 
  Protected *DEVMODEBuffer.DEVMODE 
  Protected *DEVMODEBufferCopy.DEVMODE 
  Protected ErrorMsg.S 
  Protected ModeFlag.L 
  Protected PRINTER_DEFAULTSStructure.PRINTER_DEFAULTS 
  Protected PrinterHandle.L 
  Protected Result.L 

  ; ----- Drucker Handle ermitteln
  
  PRINTER_DEFAULTSStructure\DesiredAccess = #STANDARD_RIGHTS_REQUIRED | #PRINTER_ACCESS_ADMINISTER | #PRINTER_ACCESS_USE 

  Result = OpenPrinter_(@PrinterName, @PrinterHandle, @PRINTER_DEFAULTSStructure) 
  
  If Result = #False Or PrinterHandle = 0 
    ErrorMsg = "Die Windows-Funktion OpenPrinter() ist fehlgeschlagen!"
    Result = #False 
    Goto CleanUp 
  EndIf 

  ; ----- Buffer für DEVMODE-Struktur 

  ModeFlag = 0 

  BufferSize = DocumentProperties_(0, PrinterHandle, @PrinterName, 0, 0, ModeFlag) 
  
  If BufferSize < 0 Or ModeFlag <> 0 
    ErrorMsg = "Die Größe der DEVMODE-Struktur konnte nicht ermittelt werden!" 
    Goto CleanUp 
    End 
  EndIf 

  ; ----- Speicher-Buffer für DEVMODE-Struktur 
  
  *DEVMODEBuffer = AllocateMemory(BufferSize) 
  
  If *DEVMODEBuffer = 0 
    ErrorMsg = "Die Speicheranforderung für die DEVMODE-Struktur ist gescheitert!"
    Result = #False 
    Goto CleanUp 
  EndIf 
  
  ; ----- Speicher-Buffer für Kopier der DEVMODE-Struktur 
  
  *DEVMODEBufferCopy = AllocateMemory(BufferSize) 
  
  If *DEVMODEBufferCopy = 0 
    ErrorMsg = "Die Speicheranforderung für eine Kopie der DEVMODE-Struktur ist gescheitert!" 
    Result = #False 
    Goto CleanUp 
  EndIf 

  ; ----- DEVMODE-Struktur generieren lassen
  
  Result = DocumentProperties_(0, PrinterHandle, @PrinterName, *DEVMODEBuffer, 0, #DM_OUT_BUFFER) 
  
  If Result < 0 
    ErrorMsg = "Die Windows-Funktion DocumentProperties() ist fehlgeschlagen!" 
    Result = #False 
    Goto CleanUp 
  EndIf 

  ; ----- DEVMODE-Struktur kopieren

  CopyMemory(*DEVMODEBuffer, *DEVMODEBufferCopy, BufferSize) 

  ; ----- Einzugsfach abändern

  *DEVMODEBufferCopy\dmDefaultSource = BinID
  
  ; ----- Papierformat definieren
  
  *DEVMODEBufferCopy\dmPaperSize = #DMPAPER_A4

  ; ----- Angeben, welche Parameter geändert werden sollen 

  *DEVMODEBufferCopy\dmFields = #DM_DEFAULTSOURCE | #DM_PAPERSIZE

  ; ----- DEVMODE-Struktur mit modifizierter Kopie überschreiben 

  CopyMemory(*DEVMODEBufferCopy, *DEVMODEBuffer, BufferSize) 

  ; ----- Modifizierte DEVMODE-Struktur übergeben 

  Result = DocumentProperties_(0, PrinterHandle, @PrinterName, *DEVMODEBuffer, *DEVMODEBuffer, #DM_IN_BUFFER | #DM_OUT_BUFFER) 

  If Result <> #IDOK
    ErrorMsg = "Die Übergabe der modifizierten DEVMODE-Struktur ist gescheitert!" 
    Result = #False 
  EndIf

; ----- Drucker Handle und Speicherbereiche freigeben 

CleanUp: 
  If PrinterHandle <> 0 
    ClosePrinter_(PrinterHandle) 
  EndIf 

  If *DEVMODEBufferCopy <> 0 
    FreeMemory(*DEVMODEBufferCopy) 
  EndIf 

  If Result = #False 
    If *DEVMODEBuffer <> 0 
      FreeMemory(*DEVMODEBuffer) 
    EndIf 
  
    MessageRequester("Error", ErrorMsg, #MB_ICONERROR) 
    ProcedureReturn #False 
  EndIf 

  ProcedureReturn *DEVMODEBuffer 
EndProcedure 


Define BinID.L
Define BinIDBuffer.S
Define BinNameBuffer.S
Define Buffer.S
Define DefaultPrinterName.S
Define DefaultPortName.S
Define *DEVMODEBuffer
Define DocInfo.DOCINFO
Define Driver.S
Define i.L
Define Info.S
Define NumBins.L
Define PrinterDC.L
Define Result.L
Define SelectedBinID.W
Define SelectedBinName.S
Define Text.S
Define WindowEvent.L

BinIDBuffer = Space(20 * 2)                ; maximal 20 Papiereinzugfach-IDs passen hier hinein!
BinNameBuffer = Space(20 * #BinNameLength) ; maximal 20 Papiereinzugfach-Namen passen hier hinein!
Buffer = Space(260)

; ----- Default-Druckernamen und Drucker-Port ermitteln

GetPrivateProfileString_("WINDOWS", "DEVICE", "", @Buffer, 260, "Win.Ini")
DefaultPrinterName = StringField(Buffer, 1, ",")
DefaultPortName = StringField(Buffer, 3, ",")

; ----- Namen der Fächer ermitteln

NumBins = DeviceCapabilities_(@DefaultPrinterName, @DefaultPortName, #DC_BINNAMES, @BinNameBuffer, 0)

Select NumBins
  Case -1
    MessageRequester("Fehler", "Der Aufruf der Windows-Funktion DeviceCapabilities() ist fehlgeschlagen!", #MB_ICONERROR)
    End
  Case 0
    MessageRequester("Fehler", "Der Abfrage der Papiereinzugfach-Namen wird vom Druckertreiber nicht unterstützt!", #MB_ICONERROR)
    End
EndSelect

If OpenWindow(0, 0, 0, 200, 100, "Fach-Auswahl", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
  If CreateGadgetList(WindowID(0))
    ComboBoxGadget(0, 10, 10, 180, 200)
    ButtonGadget(1, 50, 70, 100, 20, "Drucken")

    For i = 0 To NumBins - 1
      AddGadgetItem(0, -1, Trim(PeekS(@BinNameBuffer + i * #BinNameLength)))
    Next i

    SetGadgetState(0, 0)

    WindowEvent = WaitWindowEvent()

    Repeat
      WindowEvent = WaitWindowEvent()
  
      Select WindowEvent
        Case #PB_Event_CloseWindow
          End
        Case #PB_Event_Gadget
          If EventGadget() = 1 And EventType() = #PB_EventType_LeftClick
            Break
          EndIf
      EndSelect
    ForEver
  EndIf
EndIf

SelectedBinName = GetGadgetText(0)
SelectedBinID = GetGadgetState(0)

CloseWindow(0)

; ----- Einzugfach-ID ermitteln

NumBins = DeviceCapabilities_(@DefaultPrinterName, @DefaultPortName, #DC_BINS, @BinIDBuffer, 0)

Select NumBins
  Case -1
    MessageRequester("Fehler", "Der Aufruf der Windows-Funktion DeviceCapabilities() ist fehlgeschlagen!", #MB_ICONERROR)
    End
  Case 0
    MessageRequester("Fehler", "Der Abfrage der Papiereinzugfach-Namen wird vom Druckertreiber nicht unterstützt!", #MB_ICONERROR)
    End
EndSelect

SelectedBinID = PeekW(@BinIDBuffer + SelectedBinID * 2)

; ----- Papiereinzugfach wechseln

*DEVMODEBuffer = ChangeBin(DefaultPrinterName, SelectedBinID) 

If *DEVMODEBuffer = 0 
  End 
EndIf 

; ----- Test-Seite ausdrucken und dabei Papier aus gewünschtem Fach ziehen

PrinterDC = CreateDC_(@Driver, @DefaultPrinterName, 0, *DEVMODEBuffer) 

DocInfo\cbSize = SizeOf(DOCINFO) 
DocInfo\lpszDocName = @"PureBASIC Test-Seite" 
DocInfo\lpszOutput  = #Null

Text = "Diese Seite sollte aus dem Fach " + SelectedBinName + " gezogen worden sein!" 

If StartDoc_(PrinterDC, @DocInfo) > 0 
  If StartPage_(PrinterDC) > 0 
    TextOut_(PrinterDC, 300, 100, Text, Len(Text)) 
    EndPage_(PrinterDC) 
  EndIf 

  EndDoc_(PrinterDC) 
EndIf 

FreeMemory(*DEVMODEBuffer) 

If PrinterDC <> 0 
  DeleteDC_(PrinterDC) 
EndIf
MK_2007
Beiträge: 11
Registriert: 05.02.2008 17:43

Beitrag von MK_2007 »

Vielen Dank an Shardik.
Dein Code hat mir sehr weitergeholfen.
Ich wußte doch, dass hier findige Köpfe im Forum sind. :allright:
Antworten