打开打印机设置对话框并保存更改

时间:2010-05-11 11:36:39

标签: .net vb.net winapi printing pinvoke

这与this问题相同,只有一句话: 我们设法修改了printerSettings,但是我们如何将它们保存为默认的打印机设置? (原始问题不发布/回答此问题)

我现在正在使用的代码:

<DllImport("winspool.Drv", EntryPoint:="DocumentPropertiesW", SetLastError:=True, _
    ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
  Shared Function DocumentProperties(ByVal hwnd As IntPtr, ByVal hPrinter As IntPtr, _
      <MarshalAs(UnmanagedType.LPWStr)> ByVal pDeviceName As String, _
      ByVal pDevModeOutput As IntPtr, ByVal pDevModeInput As IntPtr, ByVal fMode As Integer) As Integer

   End Function

   <DllImport("kernel32.dll")> _
   Shared Function GlobalLock(ByVal hMem As IntPtr) As IntPtr

   End Function

   <DllImport("kernel32.dll")> _
   Shared Function GlobalUnlock(ByVal hMem As IntPtr) As Boolean

   End Function
   <DllImport("kernel32.dll")> _
   Shared Function GlobalFree(ByVal hMem As IntPtr) As Boolean

   End Function

   <DllImport("winspool.drv")> _
   Shared Function OpenPrinter(ByVal pPrinterName As String, ByRef hPrinter As IntPtr, ByVal pDefault As IntPtr) As Integer

   End Function

   <DllImport("winspool.drv")> _
   Private Shared Function ClosePrinter(ByVal phPrinter As IntPtr) As Integer

   End Function

(对于DocumentProperties我已尝试将pDevModeInput设为ByRef参数)

在OpenPrinterPropertiesDialog里面我尝试过:

变式1:

Public Sub OpenPrinterPropertiesDialog(ByVal iPrinterSettings As PrinterSettings)
      Dim hDevMode As IntPtr = iPrinterSettings.GetHdevmode()
      Dim pDevMode As IntPtr = GlobalLock(hDevMode)
      Dim sizeNeeded As Integer = DocumentProperties(mHandle, IntPtr.Zero, iPrinterSettings.PrinterName, pDevMode, pDevMode, 0)
      Dim devModeData As IntPtr = Marshal.AllocHGlobal(sizeNeeded)
      Dim fMode As Integer = 14
      Dim returnCode As Integer = DocumentProperties(mHandle, IntPtr.Zero, iPrinterSettings.PrinterName, devModeData, pDevMode, fMode)

      GlobalUnlock(hDevMode)
      iPrinterSettings.SetHdevmode(devModeData)
      iPrinterSettings.DefaultPageSettings.SetHdevmode(devModeData)

      GlobalFree(hDevMode)
      Marshal.FreeHGlobal(devModeData)
   End Sub

变体2:

Public Sub OpenPrinterPropertiesDialog(ByVal iPrinterSettings As PrinterSettings)
      Dim printerName As String = iPrinterSettings.PrinterName
      Dim handle As IntPtr
      OpenPrinter(printerName, handle, IntPtr.Zero)

      Dim hDevMode As IntPtr = iPrinterSettings.GetHdevmode(iPrinterSettings.DefaultPageSettings)
      Dim pDevMode As IntPtr = GlobalLock(hDevMode)
      Dim sizeNeeded As Integer = DocumentProperties(mHandle, IntPtr.Zero, iPrinterSettings.PrinterName, pDevMode, pDevMode, 0)
      Dim devModeData As IntPtr = Marshal.AllocHGlobal(sizeNeeded)
      Dim fMode As Integer = 14
      Dim returnCode As Integer = DocumentProperties(mHandle, IntPtr.Zero, iPrinterSettings.PrinterName, devModeData, pDevMode, fMode)

      GlobalUnlock(hDevMode)
      iPrinterSettings.SetHdevmode(devModeData)
      iPrinterSettings.DefaultPageSettings.SetHdevmode(devModeData)
      returnCode = DocumentProperties(IntPtr.Zero, IntPtr.Zero, iPrinterSettings.PrinterName, devModeData, pDevMode, 2)

      ClosePrinter(handle)
      GlobalFree(hDevMode)
      Marshal.FreeHGlobal(devModeData)
   End Sub

有关为何未保存更改的任何想法?

1 个答案:

答案 0 :(得分:2)

要使其正常运行,我必须根据找到的代码更改代码here(感谢 umeshb 分享它!)

我现在使用的代码(在XP上工作)是:(随意优化它)

Public Class PrinterSettingsHelper
#Region "Private Variables"
   Private gPrinter As IntPtr = New System.IntPtr()
   Private gPrinterValues As PRINTER_DEFAULTS = New PRINTER_DEFAULTS()
   Private gPInfo As PRINTER_INFO_2 = New PRINTER_INFO_2()
   Private gDevMode As DEVMODE
   Private gPtrDevMode As IntPtr
   Private gPtrPrinterInfo As IntPtr
   Private gSizeOfDevMode As Integer = 0
   Private gLastError As Integer
   Private gNBytesNeeded As Integer
   Private gNRet As Long
   Private gIntError As Integer
   Private gNTemporary As Int32
   Private gDevModeData As IntPtr
#End Region
#Region "Data structure"
   <StructLayout(LayoutKind.Sequential)> _
   Public Structure PRINTER_DEFAULTS
      Public pDatatype As Integer
      Public pDevMode As Integer
      Public DesiredAccess As Integer
   End Structure

   <StructLayout(LayoutKind.Sequential)> _
   Private Structure PRINTER_INFO_2
      <MarshalAs(UnmanagedType.LPStr)> Public pServerName As String
      <MarshalAs(UnmanagedType.LPStr)> Public pPrinterName As String
      <MarshalAs(UnmanagedType.LPStr)> Public pShareName As String
      <MarshalAs(UnmanagedType.LPStr)> Public pPortName As String
      <MarshalAs(UnmanagedType.LPStr)> Public pDriverName As String
      <MarshalAs(UnmanagedType.LPStr)> Public pComment As String
      <MarshalAs(UnmanagedType.LPStr)> Public pLocation As String
      Public pDevMode As IntPtr
      <MarshalAs(UnmanagedType.LPStr)> Public pSepFile As String
      <MarshalAs(UnmanagedType.LPStr)> Public pPrintProcessor As String
      <MarshalAs(UnmanagedType.LPStr)> Public pDatatype As String
      <MarshalAs(UnmanagedType.LPStr)> Public pParameters As String
      Public pSecurityDescriptor As IntPtr
      Public Attributes As Int32
      Public Priority As Int32
      Public DefaultPriority As Int32
      Public StartTime As Int32
      Public UntilTime As Int32
      Public Status As Int32
      Public cJobs As Int32
      Public AveragePPM As Int32
   End Structure

   Private Const CCDEVICENAME As Short = 32
   Private Const CCFORMNAME As Short = 32

   <StructLayout(LayoutKind.Sequential)> _
   Public Structure DEVMODE
      <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCDEVICENAME)> _
      Public dmDeviceName As String
      Public dmSpecVersion As Short
      Public dmDriverVersion As Short
      Public dmSize As Short
      Public dmDriverExtra As Short
      Public dmFields As Integer
      Public dmOrientation As Short
      Public dmPaperSize As Short
      Public dmPaperLength As Short
      Public dmPaperWidth As Short
      Public dmScale As Short
      Public dmCopies As Short
      Public dmDefaultSource As Short
      Public dmPrintQuality As Short
      Public dmColor As Short
      Public dmDuplex As Short
      Public dmYResolution As Short
      Public dmTTOption As Short
      Public dmCollate As Short
      <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=CCFORMNAME)> _
      Public dmFormName As String
      Public dmUnusedPadding As Short
      Public dmBitsPerPel As Short
      Public dmPelsWidth As Integer
      Public dmPelsHeight As Integer
      Public dmDisplayFlags As Integer
      Public dmDisplayFrequency As Integer
   End Structure

#End Region
#Region "Win API Def"
   <DllImport("kernel32.dll", EntryPoint:="GetLastError", SetLastError:=False, _
   ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
   Private Shared Function GetLastError() As Int32

   End Function

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

   End Function

   <DllImport("winspool.Drv", EntryPoint:="DocumentPropertiesA", SetLastError:=True, _
   ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
   Private Shared Function DocumentProperties(ByVal hwnd As IntPtr, ByVal hPrinter As IntPtr, _
    <MarshalAs(UnmanagedType.LPStr)> ByVal pDeviceNameg As String, _
   ByVal pDevModeOutput As IntPtr, ByRef pDevModeInput As IntPtr, ByVal fMode As Integer) As Integer

   End Function

   <DllImport("winspool.Drv", EntryPoint:="GetPrinterA", SetLastError:=True, _
       CharSet:=CharSet.Ansi, ExactSpelling:=True, _
       CallingConvention:=CallingConvention.StdCall)> _
   Private Shared Function GetPrinter(ByVal hPrinter As IntPtr, ByVal dwLevel As Int32, _
   ByVal pPrinter As IntPtr, ByVal dwBuf As Int32, ByRef dwNeeded As Int32) As Boolean
   End Function

   <DllImport("winspool.Drv", EntryPoint:="OpenPrinterA", _
       SetLastError:=True, CharSet:=CharSet.Ansi, _
       ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _
   Private Shared Function OpenPrinter(<MarshalAs(UnmanagedType.LPStr)> ByVal szPrinter As String, _
       ByRef hPrinter As IntPtr, ByRef pd As PRINTER_DEFAULTS) As Boolean

   End Function

   <DllImport("winspool.drv", CharSet:=CharSet.Ansi, SetLastError:=True)> _
   Private Shared Function SetPrinter(ByVal hPrinter As IntPtr, ByVal Level As Integer, _
                                      ByVal pPrinter As IntPtr, ByVal Command As Integer) As Boolean

   End Function
#End Region

#Region "Constants"
   Private Const DM_DUPLEX As Integer = 4096 '0x1000
   Private Const DM_IN_BUFFER As Integer = 8
   Private Const DM_OUT_BUFFER As Integer = 2
   Private Const PRINTER_ACCESS_ADMINISTER As Integer = 4 '0x4
   Private Const STANDARD_RIGHTS_REQUIRED As Integer = 983040 '0xF0000
   Private Const PRINTER_ALL_ACCESS As Integer = STANDARD_RIGHTS_REQUIRED Or PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE
   Private Const PRINTER_ACCESS_USE As Integer = 8 '0x8
#End Region

#Region "Function to change printer settings"
   Public Function ChangePrinterSetting(ByVal iPrinterName As String) As Boolean
      gDevMode = Me.GetPrinterSettings(iPrinterName)
      Marshal.StructureToPtr(gDevMode, gDevModeData, True)
      gPInfo.pDevMode = gDevModeData
      gPInfo.pSecurityDescriptor = IntPtr.Zero
      'bring up the printer preferences dialog
      DocumentProperties(IntPtr.Zero, gPrinter, iPrinterName, gDevModeData _
          , gPInfo.pDevMode, DM_IN_BUFFER Or DM_OUT_BUFFER Or PRINTER_ACCESS_ADMINISTER)
      'update driver dependent part of the DEVMODE 
      Marshal.StructureToPtr(gPInfo, gPtrPrinterInfo, True)
      gLastError = Marshal.GetLastWin32Error()
      gNRet = Convert.ToInt16(SetPrinter(gPrinter, 2, gPtrPrinterInfo, 0))
      If gNRet = 0 Then
         'Unable to set shared printer settings.
         gLastError = Marshal.GetLastWin32Error()
         Throw New Exception(Marshal.GetLastWin32Error().ToString)
      End If
      If gPrinter <> IntPtr.Zero Then
         ClosePrinter(gPrinter)
      End If
      Return Convert.ToBoolean(gNRet)
   End Function

   Private Function GetPrinterSettings(ByVal PrinterName As String) As DEVMODE
      Dim lDevMode As DEVMODE
      gPrinterValues.pDatatype = 0
      gPrinterValues.pDevMode = 0
      gPrinterValues.DesiredAccess = PRINTER_ALL_ACCESS
      gNRet = Convert.ToInt32(OpenPrinter(PrinterName, _
                     gPrinter, gPrinterValues))
      If gNRet = 0 Then
         gLastError = Marshal.GetLastWin32Error()
         Throw New Exception(Marshal.GetLastWin32Error().ToString())
      End If

      GetPrinter(gPrinter, 2, IntPtr.Zero, 0, gNBytesNeeded)
      If gNBytesNeeded <= 0 Then
         Throw New System.Exception("Unable to allocate memory")
      Else
         ' Allocate enough space for PRINTER_INFO_2... 
         gPtrPrinterInfo = Marshal.AllocCoTaskMem(gNBytesNeeded)
         gPtrPrinterInfo = Marshal.AllocHGlobal(gNBytesNeeded)
         'The second GetPrinter fills in all the current settings, so all you 
         'need to do is modify what you're interested in...
         gNRet = Convert.ToInt32(GetPrinter(gPrinter, 2, _
             gPtrPrinterInfo, gNBytesNeeded, gNTemporary))
         If gNRet = 0 Then
            gLastError = Marshal.GetLastWin32Error()
            Throw New Exception(Marshal.GetLastWin32Error().ToString())
         End If
         gPInfo = CType(Marshal.PtrToStructure(gPtrPrinterInfo, GetType(PRINTER_INFO_2)), PRINTER_INFO_2)
         Dim lTempBuffer As IntPtr = New IntPtr()
         If gPInfo.pDevMode = IntPtr.Zero Then
            'If GetPrinter didn't fill in the DEVMODE, try to get it by calling
            'DocumentProperties...
            Dim ptrZero As IntPtr = IntPtr.Zero
            'get the size of the devmode structure
            gSizeOfDevMode = DocumentProperties(IntPtr.Zero, gPrinter, _
                               PrinterName, ptrZero, ptrZero, 0)
            gPtrDevMode = Marshal.AllocCoTaskMem(gSizeOfDevMode)
            Dim i As Integer = DocumentProperties(IntPtr.Zero, gPrinter, PrinterName, gPtrDevMode, _
            ptrZero, DM_OUT_BUFFER)
            If (i < 0) OrElse (gPtrDevMode <> IntPtr.Zero) Then
               'Cannot get the DEVMODE structure.
               Throw New System.Exception("Cannot get DEVMODE data")
            End If
            gPInfo.pDevMode = gPtrDevMode
         End If
         gIntError = DocumentProperties(IntPtr.Zero, gPrinter, _
                   PrinterName, IntPtr.Zero, lTempBuffer, 0)
         gDevModeData = Marshal.AllocHGlobal(gIntError)
         gIntError = DocumentProperties(IntPtr.Zero, gPrinter, _
                  PrinterName, gDevModeData, lTempBuffer, 2)
         lDevMode = CType(Marshal.PtrToStructure(gDevModeData, GetType(DEVMODE)), DEVMODE)
         If (gNRet = 0) OrElse (gPrinter = IntPtr.Zero) Then
            gLastError = Marshal.GetLastWin32Error()
            Throw New Exception(Marshal.GetLastWin32Error().ToString())
         End If
         Return lDevMode
      End If
   End Function
#End Region
End Class

并使用此课程:

 Dim lPrinterpreferences As PrinterSettingsHelper = New PrinterSettingsHelper()
         lPrinterpreferences.ChangePrinterSetting("MyFavouritePrinter")