none
How do I Persist PrinterDialog settings between different documents RRS feed

  • 問題

  • I am writing an application for user documents printing. This application is supposed to be able to print multiple (say more than 100) documents at once. And some printers have stapling option and user may want to staple EACH document separately.

     

    I could show a PrinterDialog for the first document and let the application remember all settings. But different departments have different printers and printer settings. I think the application must be written in more general way like somehow persisting the selected printer settings for the next printing.

     

    For example, Internet Explorer and Acrobat PDF Reader remembers printer settings once changed by user inside the application as long as the application is running but does not change the printer's default settings (in Windows Control Panel). I want to achieve the same thing in my application.

     

    Could anybody show me how to achieve this hopefully including some code snippet?

    2008年10月27日 上午 05:03

解答

  • I resolved the issue. Pinvoke.net helped me greatly to write correct VB.NET signature of Win32 functions. Here I want to share my codes for people who are trying to get similar goal :

     

     

    Code Snippet

    Imports System.Drawing.Printing
    Imports System.Runtime.InteropServices


    Public Class PrinterNative

    'Refer http://msdn.microsoft.com/en-us/library/ms535735(VS.85).aspx
    '  http://support.microsoft.com/kb/167345
    '  http://www.pinvoke.net/default.aspx


    Private Declare Auto Function GlobalLock Lib "kernel32.dll" (ByVal handle As IntPtr) As IntPtr
    Private Declare Auto Function GlobalUnlock Lib "kernel32.dll" (ByVal handle As IntPtr) As Integer
    Private Declare Auto Function GlobalFree Lib "kernel32.dll" (ByVal handle As IntPtr) As IntPtr

    Private Declare Auto Function DocumentProperties Lib "winspool.drv" _
     (ByVal hWnd As IntPtr, ByVal hPrinter As IntPtr, ByVal pDeviceName As String, _
      ByVal pDevModeOutput As IntPtr, ByVal pDevModeInput As IntPtr, ByVal fMode As Int32) As Integer

    Public Declare Function GetPrinter Lib "winspool.drv" Alias "GetPrinterW" _
     (ByVal hPrinter As IntPtr, ByVal Level As Integer, ByVal pPrinter As IntPtr, _
      ByVal cbBuf As Integer, ByRef pcbNeeded As Integer) As Integer

    Private Declare Function SetPrinter Lib "winspool.drv" Alias "SetPrinterA" _
     (ByVal hPrinter As IntPtr, ByVal level As Integer, ByVal pPrinterInfoIn As IntPtr, _
      ByVal command As Int32) As Boolean

    <DllImport("winspool.drv", EntryPoint:="OpenPrinterA", ExactSpelling:=True, _
       SetLastError:=True, CallingConvention:=CallingConvention.StdCall, _
       CharSet:=CharSet.Ansi)> _
       Private Shared Function OpenPrinter(ByVal pPrinterName As String, _
      ByRef hPrinter As IntPtr, ByRef pDefault As PRINTER_DEFAULTS) As Boolean
       End Function

    <DllImport("winspool.drv", EntryPoint:="ClosePrinter", SetLastError:=True, ExactSpelling:=True, _
     CallingConvention:=CallingConvention.StdCall)> _
     Private Shared Function ClosePrinter(ByVal hPrinter As Int32) As Boolean
     End Function

    Declare Function GetDefaultPrinter Lib "winspool.drv" Alias "GetDefaultPrinterA" _
     (ByVal pszBuffer As System.Text.StringBuilder, ByRef pcchBuffer As Int32) As Boolean

    Declare Function SetDefaultPrinter Lib "winspool.drv" Alias "SetDefaultPrinterA" _
     (ByVal pszPrinter As String) As Boolean

    Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
     (ByVal hpvDest As IntPtr, ByVal hpvSource As IntPtr, ByVal cbCopy As Long)


    Private Structure PRINTER_DEFAULTS
     Dim pDatatype As String
     Dim pDevMode As Long
     Dim pDesiredAccess As Long
    End Structure

    Private Const STANDARD_RIGHTS_REQUIRED = &HF0000
    Private Const PRINTER_ACCESS_ADMINISTER = &H4
    Private Const PRINTER_ACCESS_USE = &H8
    Private Const PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE)

    Private Const DM_IN_BUFFER As Integer = 8
    Private Const DM_IN_PROMPT As Integer = 4
    Private Const DM_OUT_BUFFER As Integer = 2

    Private Structure PRINTER_INFO_9
      Dim pDevMode As IntPtr
    End Structure

     

    <StructLayout(LayoutKind.Sequential)> _
    Private Structure PRINTER_INFO_2
      <MarshalAs(UnmanagedType.LPTStr)> Public pServerName As String
      <MarshalAs(UnmanagedType.LPTStr)> Public pPrinterName As String
      <MarshalAs(UnmanagedType.LPTStr)> Public pShareName As String
      <MarshalAs(UnmanagedType.LPTStr)> Public pPortName As String
      <MarshalAs(UnmanagedType.LPTStr)> Public pDriverName As String
      <MarshalAs(UnmanagedType.LPTStr)> Public pComment As String
      <MarshalAs(UnmanagedType.LPTStr)> Public pLocation As String

      Public pDevMode As IntPtr

      <MarshalAs(UnmanagedType.LPTStr)> Public pSepFile As String
      <MarshalAs(UnmanagedType.LPTStr)> Public pPrintProcessor As String
      <MarshalAs(UnmanagedType.LPTStr)> Public pDatatype As String
      <MarshalAs(UnmanagedType.LPTStr)> Public pParameters As String

      Public pSecurityDescriptor As IntPtr
      Public Attributes As Integer
      Public Priority As Integer
      Public DefaultPriority As Integer
      Public StartTime As Integer
      Public UntilTime As Integer
      Public Status As Integer
      Public cJobs As Integer
      Public AveragePPM As Integer
     End Structure

     

    <StructLayout(LayoutKind.Sequential)> _
    Public Structure DEVMODE
      <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> Dim dmDeviceName As String
      Dim dmSpecVersion As Short
      Dim dmDriverVersion As Short
      Dim dmSize As Short
      Dim dmDriverExtra As Short
      Dim dmFields As Integer

      Dim dmOrientation As Short
      Dim dmPaperSize As Short
      Dim dmPaperLength As Short
      Dim dmPaperWidth As Short

      Dim dmScale As Short
      Dim dmCopies As Short
      Dim dmDefaultSource As Short
      Dim dmPrintQuality As Short
      Dim dmColor As Short
      Dim dmDuplex As Short
      Dim dmYResolution As Short
      Dim dmTTOption As Short
      Dim dmCollate As Short
      <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> Public dmFormName As String
      Dim dmLogPixels As Short
      Dim dmBitsPerPel As Integer
      Dim dmPelsWidth As Integer
      Dim dmPelsHeight As Integer
      Dim dmDisplayFlags As Integer
      Dim dmDisplayFrequency As Integer

      Dim dmICMMethod As Integer
      Dim dmICMIntent As Integer
      Dim dmMediaType As Integer
      Dim dmDitherType As Integer
      Dim dmReserved1 As Integer
      Dim dmReserved2 As Integer
      Dim dmPanningWidth As Integer
      Dim dmPanningHeight As Integer
    End Structure

     

    'Global variables
    Private PrinterName As String = ""
    Private pOriginalDEVMODE As IntPtr

     

    Public Function OpenPrinterPropertiesDialog() As Boolean
     Dim hPrinter As IntPtr
     Dim Needed As Integer
     Dim buffer As New System.Text.StringBuilder(256)

     

     'Get default printer's name
     GetDefaultPrinter(buffer, 256)
     PrinterName = buffer.ToString
     If PrinterName = "" Then
      MsgBox("Can't find default printer.")
      Return False
     End If

     

     OpenPrinter(PrinterName, hPrinter, Nothing)

     

     'Save original printer settings data (DEVMODE structure)
     Needed = DocumentProperties(Form1.Handle, hPrinter, PrinterName, Nothing, Nothing, 0)
     Dim pFullDevMode As IntPtr = Marshal.AllocHGlobal(Needed) 'buffer for DEVMODE structure
     DocumentProperties(Form1.Handle, hPrinter, PrinterName, pFullDevMode, Nothing, DM_OUT_BUFFER)
     pOriginalDEVMODE = Marshal.AllocHGlobal(Needed)
     CopyMemory(pOriginalDEVMODE, pFullDevMode, Needed)

     

     'Make desired changes by showing user a printer dialog
     Dim ret As DialogResult
     ret = DocumentProperties(Form1.Handle, hPrinter, PrinterName, pFullDevMode, Nothing, DM_IN_PROMPT Or DM_OUT_BUFFER)

     

     'Change the default settings of the printer
     If ret = DialogResult.OK Then
      Dim PI9 As New PRINTER_INFO_9
      PI9.pDevMode = pFullDevMode
      Dim pPI9 As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(PI9))
      Marshal.StructureToPtr(PI9, pPI9, True)
      SetPrinter(hPrinter, 9, pPI9, 0&)
      Marshal.FreeHGlobal(pPI9) 'pFullDevMode will be free too
     Else
      Marshal.FreeHGlobal(pFullDevMode)
     End If

     

     ClosePrinter(hPrinter)
     Return IIf(ret = DialogResult.OK, True, False)
    End Function

     

    Public Sub RestorePrinterSettings()
     Dim hPrinter As IntPtr
     If PrinterName = "" Then Exit Sub

     

     Try
      If OpenPrinter(PrinterName, hPrinter, Nothing) = False Then Exit Sub
      Dim PI9 As New PRINTER_INFO_9
      PI9.pDevMode = pOriginalDEVMODE
      Dim pPI9 As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(PI9))
      Marshal.StructureToPtr(PI9, pPI9, True)
      SetPrinter(hPrinter, 9, pPI9, 0&)
      Marshal.FreeHGlobal(pPI9) 'pOriginalDEVMODE will be free too
      ClosePrinter(hPrinter)

     

     Catch ex As Exception
      MsgBox(ex.Message)
     End Try


    End Sub
    End Class

     

    'In the main form...

    Imports CrystalDecisions.CrystalReports.Engine

    Imports CrystalDecisions.Shared

    Imports System.Collections

    Imports System.IO

     

    Public Class Form1

     

    Dim MyReportDocument As New ReportDocument

    '...

     

     Private Function printPrO(ByVal PrO As String) As String
      Dim Errormessage As String = ""

      Try
       SetReportDocumentParameters(PrO)
       MyReportDocument.PrintToPrinter(1, True, 0, 0) 'nCopies,bCollated,iStart,iEnd. Will not load dialog
      Catch ex As Exception
       Errormessage = PrO + " print failed. Error=" + ex.Message
      End Try

      Return Errormessage
     End Function

     

     Dim myPrinterNative As New PrinterNative

     

     Private Sub printAll_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrintAll.Click
      Dim nPro As Integer = ListBox1.Items.Count
      If nPro <= 0 Then Exit Sub
      Dim dlgResult As DialogResult = _
      MsgBox("It will print total " + LTrim(Str(nPro)) + " Production Orders at once." _
        + vbCr + "Do you want to continue?", MsgBoxStyle.OkCancel)
      If dlgResult = Windows.Forms.DialogResult.Cancel Then Exit Sub

     

      If myPrinterNative.OpenPrinterPropertiesDialog() = False Then
       Exit Sub
      End If

     

      Dim errorList As New ArrayList
      System.Windows.Forms.Cursor.Current = Cursors.WaitCursor


      Try
       For Each item As String In ListBox1.Items
        Dim err As String = printPrO(item.Trim)
        If err.Trim.Length > 0 Then
         errorList.Add(err)
        End If
       Next
      Catch ex As Exception
      Finally
       myPrinterNative.RestorePrinterSettings()
      End Try

     

      If errorList.Count > 0 Then
       Dim mergedString As String = ""
       Dim n As Integer = errorList.Count
       If n > 20 Then n = 20
       For i As Integer = 0 To n
        mergedString = mergedString + errorList(i) + vbCr
       Next
       MsgBox("There was one or more error in printing. " + vbCr + mergedString)
      End If

     

      System.Windows.Forms.Cursor.Current = Cursors.Default
     End Sub

    '...

    End Class

     

    2008年11月4日 上午 12:01

所有回覆

  • Hi fudata

     

    I think you’d better use Settings.settings to remember each setting changed by the user. So the next time you run your application, it can read the settings from the Settings.settings file and do not rasie a PrintDialog to let the user set again.

    Here is the step with screenshot

    Create PrintName node

    System generated code of Settings.settings

    In the system generated code, you can find the generated property name (PrinterName)

    The class name is Settings and the namespace is Test.Properties

     

    Use the following code to read settings from the Settings.settings

    Code Snippet

    Test.Properties.Settings settings = new Test.Properties.Settings();

    PrintDocument printDoc = new PrintDocument();

    printDoc.PrinterSettings.PrinterName = settings.PrinterName;

     

     

    Write setting to the Settings.settings

    Code Snippet
    settings.PrinterName = "HP xxx-xx Printer";

     

     

     

    if you want more information about this. please look at this.

    http://msdn.microsoft.com/en-us/library/aa730869(VS.80).aspx

     

    Sincerely,

    Kira Qian

    2008年10月28日 上午 07:14
  • Thank you for the feedback, Kira.

     

    Maybe I didn't explain my situation correctly. Actually it is a CrystalReport printing issue. Last time when I posted the same issue, the moderator moved my post to CrystalReport forum so I didn't exposed the document type this time. Please don't move this post to CrystalReport. The question is all about how to handle printers in general not about Crystal Reports.  

     

    Simple method which reads printer settings in printDoc.PrinterSettings and keep using it will not work because the settings we really want to persist is STAPLING option, which is printer's native ("private") data.

     

    During the time, I tried a lot of ways suggested by Microsoft about how to modify DEVMODE structure and persist it such as :

     

    How to modify printer Settings with the DocumentProperties() Function

    MSDN Windows GDI DocumentProperties Reference

     

    But I couln't make my program works and now I realized the real problem might lie in the BusinessObjects' API routine I was using.

     

    What my application is trying to achieve is to let user load several CrystalReports name in a listbox and print them all. Ideally the application should open a general printer dialog and let the user choose the printer and possibly change printer properties like stapling option. And then using the printer parameters chosen by the user, the application must print all crystal reports one by one without asking any more.

     

    BusinessObjects provides two API functions for printing reports:

     

    1. CrystalDecisions.CrystalReports.Engine.ReportDocument.PrintToPrinter

    (ByVal nCopies As Integer, ByVal collated As Boolean, ByVal startPageN As Integer, ByVal endPageN As Integer)

     

    2. CrystalDecisions.Windows.Forms.CrystalReportViewer.PrintReport()

     

    The second function opens printer dialog first and print the current report loaded in the viewer. I can't use this function because it will display printer dialog each time when it is inside a loop.

     

    The first function looked promising at first. But now it seems like that it COPIES printer's default settings (which I believe saved in Windows Registry) first overwriting the current printers' DEVMODE structure, which I modified before calling this function, and add those four arguments on top of that and prints. So whatever I played with DEVMODE before reaching this function call, my change will be negated by the original printer's default settings. 

     

    When I ran my application (with BO API function #2) after changing printer default setting with stapled option outside the application in WINDOWS PRINTING PREFRENCES dialog, it printed all crystal reports stapled beautifully. 

     

    So my question in this forum reaches to this point:

     

    Inside an application, I mean programmatically, how do I show a Printer Dialog and change permanently the printer's WINDOWS default printing preferences (in Registry maybe) by the values selected from the user including native(private) data? Of course I have to reset back to the original settings again when my print loop is done.  

     

    Thank you guys. 

    2008年10月30日 下午 09:24
  • Hi fudata

     

    I don’t think you need to show a printer setting dialog to the user when doing a loop print. Anyway, you can set all printing preferences directly to the .Net PrintDocument class. Just show the PrintDialog at the beginning of the printing process. Then set all the preferences to the next PrintDocument instance. This is the only way Winform can do.

     

    Sincerely,

    Kira Qian

    2008年10月31日 上午 04:11
  • I believe PrintDocument.PrinterSettings does not mainatain the "Native" (or Private) part of the printer's properties. At least in my test codes, it didn't keep those stapling options.  

     

    Thanks anyway.

    2008年10月31日 下午 03:56
  • I resolved the issue. Pinvoke.net helped me greatly to write correct VB.NET signature of Win32 functions. Here I want to share my codes for people who are trying to get similar goal :

     

     

    Code Snippet

    Imports System.Drawing.Printing
    Imports System.Runtime.InteropServices


    Public Class PrinterNative

    'Refer http://msdn.microsoft.com/en-us/library/ms535735(VS.85).aspx
    '  http://support.microsoft.com/kb/167345
    '  http://www.pinvoke.net/default.aspx


    Private Declare Auto Function GlobalLock Lib "kernel32.dll" (ByVal handle As IntPtr) As IntPtr
    Private Declare Auto Function GlobalUnlock Lib "kernel32.dll" (ByVal handle As IntPtr) As Integer
    Private Declare Auto Function GlobalFree Lib "kernel32.dll" (ByVal handle As IntPtr) As IntPtr

    Private Declare Auto Function DocumentProperties Lib "winspool.drv" _
     (ByVal hWnd As IntPtr, ByVal hPrinter As IntPtr, ByVal pDeviceName As String, _
      ByVal pDevModeOutput As IntPtr, ByVal pDevModeInput As IntPtr, ByVal fMode As Int32) As Integer

    Public Declare Function GetPrinter Lib "winspool.drv" Alias "GetPrinterW" _
     (ByVal hPrinter As IntPtr, ByVal Level As Integer, ByVal pPrinter As IntPtr, _
      ByVal cbBuf As Integer, ByRef pcbNeeded As Integer) As Integer

    Private Declare Function SetPrinter Lib "winspool.drv" Alias "SetPrinterA" _
     (ByVal hPrinter As IntPtr, ByVal level As Integer, ByVal pPrinterInfoIn As IntPtr, _
      ByVal command As Int32) As Boolean

    <DllImport("winspool.drv", EntryPoint:="OpenPrinterA", ExactSpelling:=True, _
       SetLastError:=True, CallingConvention:=CallingConvention.StdCall, _
       CharSet:=CharSet.Ansi)> _
       Private Shared Function OpenPrinter(ByVal pPrinterName As String, _
      ByRef hPrinter As IntPtr, ByRef pDefault As PRINTER_DEFAULTS) As Boolean
       End Function

    <DllImport("winspool.drv", EntryPoint:="ClosePrinter", SetLastError:=True, ExactSpelling:=True, _
     CallingConvention:=CallingConvention.StdCall)> _
     Private Shared Function ClosePrinter(ByVal hPrinter As Int32) As Boolean
     End Function

    Declare Function GetDefaultPrinter Lib "winspool.drv" Alias "GetDefaultPrinterA" _
     (ByVal pszBuffer As System.Text.StringBuilder, ByRef pcchBuffer As Int32) As Boolean

    Declare Function SetDefaultPrinter Lib "winspool.drv" Alias "SetDefaultPrinterA" _
     (ByVal pszPrinter As String) As Boolean

    Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
     (ByVal hpvDest As IntPtr, ByVal hpvSource As IntPtr, ByVal cbCopy As Long)


    Private Structure PRINTER_DEFAULTS
     Dim pDatatype As String
     Dim pDevMode As Long
     Dim pDesiredAccess As Long
    End Structure

    Private Const STANDARD_RIGHTS_REQUIRED = &HF0000
    Private Const PRINTER_ACCESS_ADMINISTER = &H4
    Private Const PRINTER_ACCESS_USE = &H8
    Private Const PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED Or PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE)

    Private Const DM_IN_BUFFER As Integer = 8
    Private Const DM_IN_PROMPT As Integer = 4
    Private Const DM_OUT_BUFFER As Integer = 2

    Private Structure PRINTER_INFO_9
      Dim pDevMode As IntPtr
    End Structure

     

    <StructLayout(LayoutKind.Sequential)> _
    Private Structure PRINTER_INFO_2
      <MarshalAs(UnmanagedType.LPTStr)> Public pServerName As String
      <MarshalAs(UnmanagedType.LPTStr)> Public pPrinterName As String
      <MarshalAs(UnmanagedType.LPTStr)> Public pShareName As String
      <MarshalAs(UnmanagedType.LPTStr)> Public pPortName As String
      <MarshalAs(UnmanagedType.LPTStr)> Public pDriverName As String
      <MarshalAs(UnmanagedType.LPTStr)> Public pComment As String
      <MarshalAs(UnmanagedType.LPTStr)> Public pLocation As String

      Public pDevMode As IntPtr

      <MarshalAs(UnmanagedType.LPTStr)> Public pSepFile As String
      <MarshalAs(UnmanagedType.LPTStr)> Public pPrintProcessor As String
      <MarshalAs(UnmanagedType.LPTStr)> Public pDatatype As String
      <MarshalAs(UnmanagedType.LPTStr)> Public pParameters As String

      Public pSecurityDescriptor As IntPtr
      Public Attributes As Integer
      Public Priority As Integer
      Public DefaultPriority As Integer
      Public StartTime As Integer
      Public UntilTime As Integer
      Public Status As Integer
      Public cJobs As Integer
      Public AveragePPM As Integer
     End Structure

     

    <StructLayout(LayoutKind.Sequential)> _
    Public Structure DEVMODE
      <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> Dim dmDeviceName As String
      Dim dmSpecVersion As Short
      Dim dmDriverVersion As Short
      Dim dmSize As Short
      Dim dmDriverExtra As Short
      Dim dmFields As Integer

      Dim dmOrientation As Short
      Dim dmPaperSize As Short
      Dim dmPaperLength As Short
      Dim dmPaperWidth As Short

      Dim dmScale As Short
      Dim dmCopies As Short
      Dim dmDefaultSource As Short
      Dim dmPrintQuality As Short
      Dim dmColor As Short
      Dim dmDuplex As Short
      Dim dmYResolution As Short
      Dim dmTTOption As Short
      Dim dmCollate As Short
      <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=32)> Public dmFormName As String
      Dim dmLogPixels As Short
      Dim dmBitsPerPel As Integer
      Dim dmPelsWidth As Integer
      Dim dmPelsHeight As Integer
      Dim dmDisplayFlags As Integer
      Dim dmDisplayFrequency As Integer

      Dim dmICMMethod As Integer
      Dim dmICMIntent As Integer
      Dim dmMediaType As Integer
      Dim dmDitherType As Integer
      Dim dmReserved1 As Integer
      Dim dmReserved2 As Integer
      Dim dmPanningWidth As Integer
      Dim dmPanningHeight As Integer
    End Structure

     

    'Global variables
    Private PrinterName As String = ""
    Private pOriginalDEVMODE As IntPtr

     

    Public Function OpenPrinterPropertiesDialog() As Boolean
     Dim hPrinter As IntPtr
     Dim Needed As Integer
     Dim buffer As New System.Text.StringBuilder(256)

     

     'Get default printer's name
     GetDefaultPrinter(buffer, 256)
     PrinterName = buffer.ToString
     If PrinterName = "" Then
      MsgBox("Can't find default printer.")
      Return False
     End If

     

     OpenPrinter(PrinterName, hPrinter, Nothing)

     

     'Save original printer settings data (DEVMODE structure)
     Needed = DocumentProperties(Form1.Handle, hPrinter, PrinterName, Nothing, Nothing, 0)
     Dim pFullDevMode As IntPtr = Marshal.AllocHGlobal(Needed) 'buffer for DEVMODE structure
     DocumentProperties(Form1.Handle, hPrinter, PrinterName, pFullDevMode, Nothing, DM_OUT_BUFFER)
     pOriginalDEVMODE = Marshal.AllocHGlobal(Needed)
     CopyMemory(pOriginalDEVMODE, pFullDevMode, Needed)

     

     'Make desired changes by showing user a printer dialog
     Dim ret As DialogResult
     ret = DocumentProperties(Form1.Handle, hPrinter, PrinterName, pFullDevMode, Nothing, DM_IN_PROMPT Or DM_OUT_BUFFER)

     

     'Change the default settings of the printer
     If ret = DialogResult.OK Then
      Dim PI9 As New PRINTER_INFO_9
      PI9.pDevMode = pFullDevMode
      Dim pPI9 As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(PI9))
      Marshal.StructureToPtr(PI9, pPI9, True)
      SetPrinter(hPrinter, 9, pPI9, 0&)
      Marshal.FreeHGlobal(pPI9) 'pFullDevMode will be free too
     Else
      Marshal.FreeHGlobal(pFullDevMode)
     End If

     

     ClosePrinter(hPrinter)
     Return IIf(ret = DialogResult.OK, True, False)
    End Function

     

    Public Sub RestorePrinterSettings()
     Dim hPrinter As IntPtr
     If PrinterName = "" Then Exit Sub

     

     Try
      If OpenPrinter(PrinterName, hPrinter, Nothing) = False Then Exit Sub
      Dim PI9 As New PRINTER_INFO_9
      PI9.pDevMode = pOriginalDEVMODE
      Dim pPI9 As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(PI9))
      Marshal.StructureToPtr(PI9, pPI9, True)
      SetPrinter(hPrinter, 9, pPI9, 0&)
      Marshal.FreeHGlobal(pPI9) 'pOriginalDEVMODE will be free too
      ClosePrinter(hPrinter)

     

     Catch ex As Exception
      MsgBox(ex.Message)
     End Try


    End Sub
    End Class

     

    'In the main form...

    Imports CrystalDecisions.CrystalReports.Engine

    Imports CrystalDecisions.Shared

    Imports System.Collections

    Imports System.IO

     

    Public Class Form1

     

    Dim MyReportDocument As New ReportDocument

    '...

     

     Private Function printPrO(ByVal PrO As String) As String
      Dim Errormessage As String = ""

      Try
       SetReportDocumentParameters(PrO)
       MyReportDocument.PrintToPrinter(1, True, 0, 0) 'nCopies,bCollated,iStart,iEnd. Will not load dialog
      Catch ex As Exception
       Errormessage = PrO + " print failed. Error=" + ex.Message
      End Try

      Return Errormessage
     End Function

     

     Dim myPrinterNative As New PrinterNative

     

     Private Sub printAll_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrintAll.Click
      Dim nPro As Integer = ListBox1.Items.Count
      If nPro <= 0 Then Exit Sub
      Dim dlgResult As DialogResult = _
      MsgBox("It will print total " + LTrim(Str(nPro)) + " Production Orders at once." _
        + vbCr + "Do you want to continue?", MsgBoxStyle.OkCancel)
      If dlgResult = Windows.Forms.DialogResult.Cancel Then Exit Sub

     

      If myPrinterNative.OpenPrinterPropertiesDialog() = False Then
       Exit Sub
      End If

     

      Dim errorList As New ArrayList
      System.Windows.Forms.Cursor.Current = Cursors.WaitCursor


      Try
       For Each item As String In ListBox1.Items
        Dim err As String = printPrO(item.Trim)
        If err.Trim.Length > 0 Then
         errorList.Add(err)
        End If
       Next
      Catch ex As Exception
      Finally
       myPrinterNative.RestorePrinterSettings()
      End Try

     

      If errorList.Count > 0 Then
       Dim mergedString As String = ""
       Dim n As Integer = errorList.Count
       If n > 20 Then n = 20
       For i As Integer = 0 To n
        mergedString = mergedString + errorList(i) + vbCr
       Next
       MsgBox("There was one or more error in printing. " + vbCr + mergedString)
      End If

     

      System.Windows.Forms.Cursor.Current = Cursors.Default
     End Sub

    '...

    End Class

     

    2008年11月4日 上午 12:01