This is the same as this question, with one remark: We manage to get the printerSettings modified, but how can we save them back as the default printer settings? (the original question does not post/answer this)
The code I'm using right now:
<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
(for DocumentProperties
I've tried also making pDevModeInput
a ByRef
parameter)
And inside OpenPrinterPropertiesDialog I have tried:
Variant 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
Variant 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)
开发者_JS百科 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
Any ideas of why the changes are not saved back?
To get it working I had to change the code based on the code found here (thanks umeshb for sharing it!)
The code I'm using right now (working on XP) is: (feel free to optimize it)
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
and to use this class:
Dim lPrinterpreferences As PrinterSettingsHelper = New PrinterSettingsHelper()
lPrinterpreferences.ChangePrinterSetting("MyFavouritePrinter")
精彩评论