|
I've tried changing the printer settings but it doesn't work. It always defaults to what the printer's settings are. Please help
|
|
|
|
|
works fine for me
|
|
|
|
|
Imports System
Imports System.Runtime.InteropServices
Imports System.ComponentModel
Public Class PrinterData
Public Duplex As Short
Public source As Short
Public Orientation As Short
Public Size As Short
End Class
Public Class PrinterSettings
#Region "Private Variables"
Private hPrinter As IntPtr = New System.IntPtr()
Private PrinterValues As New PRINTER_DEFAULTS()
Private pinfo As New PRINTER_INFO_2()
Private dm As DEVMODE
Private ptrDM As IntPtr
Private ptrPrinterInfo As IntPtr
Private sizeOfDevMode As Integer = 0
Private lastError As Integer
Private nBytesNeeded As Integer
Private nRet As Long
Private intError As Integer
Private nJunk As Integer
Private yDevModeData As IntPtr
#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)]
' static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter,
' out IntPtr hPrinter, ref PRINTER_DEFAULTS pd) '
' [ DllImport( "winspool.drv",CharSet=CharSet.Unicode,ExactSpelling=false,
' CallingConvention=CallingConvention.StdCall )]
' public static extern long OpenPrinter(string pPrinterName,
' ref IntPtr phPrinter, int pDefault);
'[DllImport("winspool.Drv", EntryPoint="OpenPrinterA",
' SetLastError=true, CharSet=CharSet.Ansi,
' ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
' static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter,
' out IntPtr hPrinter, ref PRINTER_DEFAULTS pd);
'
<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
'[DllImport("winspool.drv", CharSet=CharSet.Ansi, SetLastError=true)]
' private static extern bool SetPrinter(IntPtr hPrinter, int Level, IntPtr
' pPrinter, int Command);
' Wrapper for Win32 message formatter.
'[DllImport("kernel32.dll", CharSet=System.Runtime.InteropServices.CharSet.Auto)]
' private unsafe static extern int FormatMessage( int dwFlags,
' ref IntPtr pMessageSource, ' int dwMessageID,
' int dwLanguageID, ' ref string lpBuffer, ' int nSize,
' IntPtr* pArguments);
#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, CharSet=CharSet.Auto)]
' public struct PRINTER_DEFAULTS ' { ' public int pDataType;
' public IntPtr pDevMode; ' public ACCESS_MASK DesiredAccess;
' }
<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 "Constants"
Private Const DM_DUPLEX As Integer = 4096
Private Const DM_IN_BUFFER As Integer = 8
Private Const DM_OUT_BUFFER As Integer = 2
Private Const PRINTER_ACCESS_ADMINISTER As Integer = 4
Private Const PRINTER_ACCESS_USE As Integer = 8
Private Const STANDARD_RIGHTS_REQUIRED As Integer = 983040
Private Const PRINTER_ALL_ACCESS As Integer = (STANDARD_RIGHTS_REQUIRED Or PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE)
#End Region
#Region "Function to change printer settings"
Public Function ChangePrinterSetting(ByVal PrinterName As String, ByVal PS As PrinterData) As Boolean
If (DirectCast(PS.Duplex, Short) < 1) OrElse (DirectCast(PS.Duplex, Short) > 3) Then
Throw New ArgumentOutOfRangeException("nDuplexSetting", "nDuplexSetting is incorrect.")
Else
dm = Me.GetPrinterSettings(PrinterName)
dm.dmDefaultSource = DirectCast(PS.source, Short)
dm.dmOrientation = DirectCast(PS.Orientation, Short)
dm.dmPaperSize = DirectCast(PS.Size, Short)
dm.dmDuplex = DirectCast(PS.Duplex, Short)
Marshal.StructureToPtr(dm, yDevModeData, True)
pinfo.pDevMode = yDevModeData
pinfo.pSecurityDescriptor = IntPtr.Zero
'update driver dependent part of the DEVMODE
' 1 = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, yDevModeData
' , ref pinfo.pDevMode, (DM_IN_BUFFER | DM_OUT_BUFFER));
Marshal.StructureToPtr(pinfo, ptrPrinterInfo, True)
lastError = Marshal.GetLastWin32Error()
nRet = Convert.ToInt16(SetPrinter(hPrinter, 2, ptrPrinterInfo, 0))
If nRet = 0 Then
'Unable to set shared printer settings.
lastError = Marshal.GetLastWin32Error()
'string myErrMsg = GetErrorMessage(lastError);
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
If hPrinter <> IntPtr.Zero Then
ClosePrinter(hPrinter)
End If
Return Convert.ToBoolean(nRet)
End If
End Function
Private Function GetPrinterSettings(ByVal PrinterName As String) As DEVMODE
Dim PData As New PrinterData()
Dim dm As DEVMODE
Const PRINTER_ACCESS_ADMINISTER As Integer = 4
Const PRINTER_ACCESS_USE As Integer = 8
Const PRINTER_ALL_ACCESS As Integer = (STANDARD_RIGHTS_REQUIRED Or PRINTER_ACCESS_ADMINISTER Or PRINTER_ACCESS_USE)
PrinterValues.pDatatype = 0
PrinterValues.pDevMode = 0
PrinterValues.DesiredAccess = PRINTER_ALL_ACCESS
nRet = Convert.ToInt32(OpenPrinter(PrinterName, hPrinter, PrinterValues))
If nRet = 0 Then
lastError = Marshal.GetLastWin32Error()
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
GetPrinter(hPrinter, 2, IntPtr.Zero, 0, nBytesNeeded)
If nBytesNeeded <= 0 Then
Throw New System.Exception("Unable to allocate memory")
Else
' Allocate enough space for PRINTER_INFO_2...
ptrPrinterInfo = Marshal.AllocCoTaskMem(nBytesNeeded)
ptrPrinterInfo = Marshal.AllocHGlobal(nBytesNeeded)
' The second GetPrinter fills in all the current settings, so all you
' need to do is modify what you're interested in...
nRet = Convert.ToInt32(GetPrinter(hPrinter, 2, ptrPrinterInfo, nBytesNeeded, nJunk))
If nRet = 0 Then
lastError = Marshal.GetLastWin32Error()
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
pinfo = DirectCast(Marshal.PtrToStructure(ptrPrinterInfo, GetType(PRINTER_INFO_2)), PRINTER_INFO_2)
Dim Temp As New IntPtr()
If pinfo.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
sizeOfDevMode = DocumentProperties(IntPtr.Zero, hPrinter, PrinterName, ptrZero, ptrZero, 0)
ptrDM = Marshal.AllocCoTaskMem(sizeOfDevMode)
Dim i As Integer
i = DocumentProperties(IntPtr.Zero, hPrinter, PrinterName, ptrDM, ptrZero, DM_OUT_BUFFER)
If (i < 0) OrElse (ptrDM = IntPtr.Zero) Then
'Cannot get the DEVMODE structure.
Throw New System.Exception("Cannot get DEVMODE data")
End If
pinfo.pDevMode = ptrDM
End If
intError = DocumentProperties(IntPtr.Zero, hPrinter, PrinterName, IntPtr.Zero, Temp, 0)
'IntPtr yDevModeData = Marshal.AllocCoTaskMem(i1);
yDevModeData = Marshal.AllocHGlobal(intError)
intError = DocumentProperties(IntPtr.Zero, hPrinter, PrinterName, yDevModeData, Temp, 2)
dm = DirectCast(Marshal.PtrToStructure(yDevModeData, GetType(DEVMODE)), DEVMODE)
'nRet = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, yDevModeData
' , ref yDevModeData, (DM_IN_BUFFER | DM_OUT_BUFFER));
If (nRet = 0) OrElse (hPrinter = IntPtr.Zero) Then
lastError = Marshal.GetLastWin32Error()
'string myErrMsg = GetErrorMessage(lastError);
Throw New Win32Exception(Marshal.GetLastWin32Error())
End If
Return dm
End If
End Function
#End Region
End Class
|
|
|
|
|
Well - it does, but you may need to specify PRINTER_DEFAULTS.DesiredAccess -SERVER_ALL_ACCESS instead or PRINTER_ALL_ACCESS.
|
|
|
|
|
Can you explain this with more detail please?
|
|
|
|
|
Surely...I'll have to explain in VB.NET though...
When you call OpenPrinter you can pass a PRINTER_DEFAULTS structure to specify the desired access you want on that printer:
<DllImport("winspool.drv", EntryPoint:="OpenPrinter", _
SetLastError:=True, CharSet:=CharSet.Ansi, _
ExactSpelling:=False, _
CallingConvention:=CallingConvention.StdCall)> _
Public Function OpenPrinter(<InAttribute()> ByVal pPrinterName As String, _
<OutAttribute()> ByRef phPrinter As Int32, _
<InAttribute(), MarshalAs(UnmanagedType.LPStruct)> ByVal pDefault As PRINTER_DEFAULTS _
) As Boolean
End Function
This structure is:-
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _
Friend Class PRINTER_DEFAULTS
Public lpDataType As Int32
Public lpDevMode As Int32
<MarshalAs(UnmanagedType.U4)> Public DesiredAccess As PrinterAccessRights
End Class
where the DesiredAccess is a combination of:-
<FlagsAttribute()> _
Public Enum PrinterAccessRights
' READ_CONTROL - Allowed to read printer information
READ_CONTROL = &H20000
' WRITE_DAC - Allowed to write device access control info
WRITE_DAC = &H40000
' WRITE_OWNER - Allowed to change the object owner
WRITE_OWNER = &H80000
' SERVER_ACCESS_ADMINISTER
SERVER_ACCESS_ADMINISTER = &H1
' SERVER_ACCESS_ENUMERATE
SERVER_ACCESS_ENUMERATE = &H2
' PRINTER_ACCESS_ADMINISTER Allows administration of a printer
PRINTER_ACCESS_ADMINISTER = &H4
' PRINTER_ACCESS_USE Allows printer general use (printing, querying)
PRINTER_ACCESS_USE = &H8
' PRINTER_ALL_ACCESS Allows use and administration.
PRINTER_ALL_ACCESS = &HF000C
' SERVER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SERVER_ACCESS_ADMINISTER | SERVER_ACCESS_ENUMERATE)
SERVER_ALL_ACCESS = &HF0003
End Enum
|
|
|
|
|
Hi Duncan,
I modified my program according to your reply and tried using SERVER_ALL_ACCESS, but I still get the "ACCESS IS DENIED" error. Was your program working fine with the network printer?
Thank you.
|
|
|
|
|
It was (is) - do you have modify rights on the server printer from Control Panel?
If not, try SERVER_ACCESS_USE
|
|
|
|
|
|
I have use this code, but Status field after GetPrinter function call is always 0. Why? How can I solve it?
Thanks,
Ana
Ana
|
|
|
|
|
Yes, I have the same result.
Reason is:
http://support.microsoft.com/kb/160129[^]
says:
There is one fundamental premise that must be true to determine the state of a physical printer: the Spooler must be attempting to send a print job to the physical printer. This is the only time the state of the printer is reported by the port monitor.
Luc Pattyn
|
|
|
|
|
I cannot change printer settings like other guys.
I do get my printer default settings with API you have provided but when I set my own parameters they do not reflect in printer settings.
I cannot figiure out what is going on?
Is anybody here who can provide working sample?
P.S. Don't you should set dmFlags when updating DEVMODE? By the way it does not helps.
Best regards.
Bartosz Węgielewski
|
|
|
|
|
Hi ,
This code is not working for my application.
I am using ProcessStartInfo class to print file.
So i am changing printer settings globally.
But it is taking all default printer settings.
I wonder Y.
|
|
|
|
|
So did it for me.
Does it work from your side now?
Help!
|
|
|
|
|
yes, it does with modifications according to C#.
|
|
|
|
|
hi kingmax,
I'm working on a project that aims at monitorint printing jobs. To achieve this I'm copying spl and shd files to a temporary folder inorder to parse them to get data I want. I've found this article which I think is written by you : http://blog.csdn.net/kingmax54212008/article/details/5567169[^]
Could you please tell me how can I retreive page count from the spl files? Thanks in advance
|
|
|
|
|
In the code below, aren't the first two
lastError = Marshal.GetLastWin32Error();
lines are unnecessary? (Since return values are not used)
Marshal.StructureToPtr(pinfo,ptrPrinterInfo,true);
lastError = Marshal.GetLastWin32Error();
nRet = Convert.ToInt16(SetPrinter(hPrinter, 2, ptrPrinterInfo, 0));
if (nRet == 0)
{
//Unable to set shared printer settings.
lastError = Marshal.GetLastWin32Error();
//string myErrMsg = GetErrorMessage(lastError);
throw new Win32Exception(Marshal.GetLastWin32Error());
}
|
|
|
|
|
I noticed you weren't marshalling the extra printer-specific information designated w/ DEVMODE.dmDriverExtra. Did you figure out a clever way of doing this?
|
|
|
|
|
First of all, great work - there aren't many articles out there on doing this in .NET (in fact yours might be the only one!)
Been testing this class quite extensively and I noticed a probable *bug*(?) on my machine which is on WinXP.
Background: I'm using IE to programatically render and print web pages to PDF with the PDF995 print driver which can be found at (www.pdf995.com)
I've populated a list of page sizes defined for the printer and am setting them in code before sending the job to print. I noticed that some print size selections work and some didn't.
That was odd but then I noticed that only non-custom kinds of page settings were applied. Custom page settings result in the driver falling back to a fixed default size.
However, if I manually go through IE and set the page size in the page settings dialog, somehow they work! So IE must be doing something differently that works.
Been looking around for hours but there's not much info on the 'net regarding this... anyone faced a similar problem or better still, solved it?
Any ideas anyone?
paul
|
|
|
|
|
Hi
I'm trying to execute the code u've given. but where ever I change the setting of the printer (like... papersource, orientation...) it is not getting reflected into my printer driver properties. How do I make those settings permenent ?
karthik
|
|
|
|
|
This is just a helpful hint. I check the values of the enumerations defined in System.Drawing.Printing, and there values map directly to the short values in the DEVMODE structure. Knowing this I modified the above code to work off of the PageSettings, and PaperSettings rather than using the custom PrinterData class that was defined in on of the threads.
Here is the modifications that I made based on reusing the enumeration/classes already in the .NET framework:
using System;
using System.Runtime.InteropServices;
using System.Drawing.Printing;
using System.ComponentModel;
using NowDocs.Util;
namespace CustomprinterSettings
{
#region "Data structure"
#region PRINTER_DEFAULTS
[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_DEFAULTS
{
public int pDatatype;
public int pDevMode;
public int DesiredAccess;
}
#endregion PRINTER_DEFAULTS
#region PRINTER_INFO_2
[StructLayout(LayoutKind.Sequential)]
struct PRINTER_INFO_2
{
[MarshalAs(UnmanagedType.LPStr)] public string pServerName;
[MarshalAs(UnmanagedType.LPStr)] public string pPrinterName;
[MarshalAs(UnmanagedType.LPStr)] public string pShareName;
[MarshalAs(UnmanagedType.LPStr)] public string pPortName;
[MarshalAs(UnmanagedType.LPStr)] public string pDriverName;
[MarshalAs(UnmanagedType.LPStr)] public string pComment;
[MarshalAs(UnmanagedType.LPStr)] public string pLocation;
public IntPtr pDevMode;
[MarshalAs(UnmanagedType.LPStr)] public string pSepFile;
[MarshalAs(UnmanagedType.LPStr)] public string pPrintProcessor;
[MarshalAs(UnmanagedType.LPStr)] public string pDatatype;
[MarshalAs(UnmanagedType.LPStr)] public string pParameters;
public IntPtr pSecurityDescriptor;
public Int32 Attributes;
public Int32 Priority;
public Int32 DefaultPriority;
public Int32 StartTime;
public Int32 UntilTime;
public Int32 Status;
public Int32 cJobs;
public Int32 AveragePPM;
}
#endregion PRINTER_INFO_2
#region DEVMODE
[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string dmDeviceName;
public short dmSpecVersion;
public short dmDriverVersion;
public short dmSize;
public short dmDriverExtra;
public int dmFields;
public short dmOrientation;
public short dmPaperSize;
public short dmPaperLength;
public short dmPaperWidth;
public short dmScale;
public short dmCopies;
public short dmDefaultSource;
public short dmPrintQuality;
public short dmColor;
public short dmDuplex;
public short dmYResolution;
public short dmTTOption;
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string dmFormName;
public short dmUnusedPadding;
public short dmBitsPerPel;
public int dmPelsWidth;
public int dmPelsHeight;
public int dmDisplayFlags;
public int dmDisplayFrequency;
}
#endregion DEVMODE
#endregion "Data structure"
#region PrinterConfiguration
public class PrinterConfiguration
{
#region "Private Variables"
private IntPtr _hPrinter = new System.IntPtr() ;
private PRINTER_DEFAULTS _PrinterValues = new PRINTER_DEFAULTS();
private PRINTER_INFO_2 _pinfo = new PRINTER_INFO_2();
private DEVMODE _Devmode;
private IntPtr _PtrDM;
private IntPtr _PtrPrinterInfo;
private int _SizeOfDevMode = 0;
private int _LastError;
private int _NBytesNeeded;
private long _NRet;
private int _IntError;
private System.Int32 _NJunk;
private IntPtr _YDevModeData;
#endregion
#region "Win API Def"
[DllImport("kernel32.dll", EntryPoint="GetLastError", SetLastError=false,
ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
private static extern Int32 GetLastError();
[DllImport("winspool.Drv", EntryPoint="ClosePrinter", SetLastError=true,
ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
private static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint="DocumentPropertiesA", SetLastError=true,
ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
private static extern int DocumentProperties (IntPtr hwnd, IntPtr hPrinter,
[MarshalAs(UnmanagedType.LPStr)] string pDeviceNameg,
IntPtr pDevModeOutput, ref IntPtr pDevModeInput, int fMode);
[DllImport("winspool.Drv", EntryPoint="GetPrinterA", SetLastError=true, CharSet=CharSet.Ansi,
ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
private static extern bool GetPrinter(IntPtr hPrinter, Int32 dwLevel,
IntPtr pPrinter, Int32 dwBuf, out Int32 dwNeeded);
[DllImport("winspool.Drv", EntryPoint="OpenPrinterA", SetLastError=true, CharSet=CharSet.Ansi,
ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
private static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter,
out IntPtr hPrinter, ref PRINTER_DEFAULTS pd);
[DllImport("winspool.drv", CharSet=CharSet.Ansi, SetLastError=true)]
private static extern bool SetPrinter(IntPtr hPrinter, int Level, IntPtr
pPrinter, int Command);
#endregion
#region "Constants"
private const int DM_DUPLEX = 0x1000;
private const int DM_IN_BUFFER = 8;
private const int DM_OUT_BUFFER = 2;
private const int PRINTER_ACCESS_ADMINISTER = 0x4;
private const int PRINTER_ACCESS_USE = 0x8;
private const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
private const int PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE);
#endregion
#region "Function to change printer settings"
#region ChangePrinterPaperSize(string PrinterName,PaperSize paperSize)
public bool ChangePrinterPaperSize (string printerName, PaperSize paperSize)
{
try
{
_Devmode = this.GetPrinterSettings( printerName);
_Devmode.dmPaperSize =(short)paperSize.Kind;
if (paperSize.Kind == PaperKind.Custom)
{
_Devmode.dmPaperWidth =
Convert.ToInt16 ((double)Math.Round (((Convert.ToDouble (pageSettings.PaperSize.Width))/100D)*25.4D*10D));
_Devmode.dmPaperLength =
Convert.ToInt16 ((double)Math.Round ((Convert.ToDouble (pageSettings.PaperSize.Height)/100D)*25.4D*10D));
}
Marshal.StructureToPtr( _Devmode,_YDevModeData,true);
_pinfo.pDevMode = _YDevModeData;
_pinfo.pSecurityDescriptor = IntPtr.Zero;
Marshal.StructureToPtr(_pinfo,_PtrPrinterInfo,true);
_LastError = Marshal.GetLastWin32Error();
_NRet = Convert.ToInt16(SetPrinter(_hPrinter, 2, _PtrPrinterInfo, 0));
if (_NRet == 0)
{
//Unable to set shared printer settings.
_LastError = Marshal.GetLastWin32Error();
//string myErrMsg = GetErrorMessage(_LastError);
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
finally
{
if (_hPrinter != IntPtr.Zero)
{
ClosePrinter(_hPrinter);
}
}
return Convert.ToBoolean(_NRet);
}
#endregion ChangePrinterPaperSize(string PrinterName,PrinterData PS)
#region ChangePrinterOrientation(string PrinterName,bool landscape)
public bool ChangePrinterOrientation (string printerName, bool landscape)
{
try
{
_Devmode = this.GetPrinterSettings( printerName);
_Devmode.dmOrientation = (short)((landscape)?2:1);
Marshal.StructureToPtr( _Devmode,_YDevModeData,true);
_pinfo.pDevMode = _YDevModeData;
_pinfo.pSecurityDescriptor = IntPtr.Zero;
Marshal.StructureToPtr(_pinfo,_PtrPrinterInfo,true);
_LastError = Marshal.GetLastWin32Error();
_NRet = Convert.ToInt16(SetPrinter(_hPrinter, 2, _PtrPrinterInfo, 0));
if (_NRet == 0)
{
//Unable to set shared printer settings.
_LastError = Marshal.GetLastWin32Error();
//string myErrMsg = GetErrorMessage(_LastError);
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
finally
{
if (_hPrinter != IntPtr.Zero)
{
ClosePrinter(_hPrinter);
}
}
return Convert.ToBoolean(_NRet);
}
#endregion ChangePrinterOrientation(string PrinterName,bool landscape)
#region ChangePrinterSetting(string PrinterName,PageSettings pageSettings)
public bool ChangePrinterSetting(string PrinterName,PageSettings pageSettings)
{
try
{
_Devmode = this.GetPrinterSettings( PrinterName);
_Devmode.dmDefaultSource =(short)pageSettings.PaperSource.Kind;
_Devmode.dmOrientation = (short)((pageSettings.Landscape)?2:1);
_Devmode.dmPaperSize =(short)pageSettings.PaperSize.Kind;
if (pageSettings.PaperSize.Kind == PaperKind.Custom)
{
_Devmode.dmPaperWidth =
Convert.ToInt16 ((double)Math.Round (((Convert.ToDouble (pageSettings.PaperSize.Width))/100D)*25.4D*10D));
_Devmode.dmPaperLength =
Convert.ToInt16 ((double)Math.Round ((Convert.ToDouble (pageSettings.PaperSize.Height)/100D)*25.4D*10D));
}
Marshal.StructureToPtr( _Devmode,_YDevModeData,true);
_pinfo.pDevMode = _YDevModeData;
_pinfo.pSecurityDescriptor = IntPtr.Zero;
/*update driver dependent part of the DEVMODE
1 = DocumentProperties(IntPtr.Zero, _hPrinter, sPrinterName, _YDevModeData
, ref _pinfo.pDevMode, (DM_IN_BUFFER | DM_OUT_BUFFER));*/
Marshal.StructureToPtr(_pinfo,_PtrPrinterInfo,true);
_LastError = Marshal.GetLastWin32Error();
_NRet = Convert.ToInt16(SetPrinter(_hPrinter, 2, _PtrPrinterInfo, 0));
if (_NRet == 0)
{
//Unable to set shared printer settings.
_LastError = Marshal.GetLastWin32Error();
//string myErrMsg = GetErrorMessage(_LastError);
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
finally
{
if (_hPrinter != IntPtr.Zero)
{
ClosePrinter(_hPrinter);
}
}
return Convert.ToBoolean(_NRet);
}
#endregion ChangePrinterSetting(string PrinterName,PageSettings pageSettings)
#region ChangePrinterSetting(string PrinterName,PageSettings pageSettings, Duplex duplex)
public bool ChangePrinterSetting(string PrinterName,PageSettings pageSettings, Duplex duplex)
{
try
{
_Devmode = this.GetPrinterSettings( PrinterName);
_Devmode.dmDefaultSource =(short)pageSettings.PaperSource.Kind;
_Devmode.dmOrientation = (short)((pageSettings.Landscape)?2:1);
_Devmode.dmPaperSize =(short)pageSettings.PaperSize.Kind;
if (pageSettings.PaperSize.Kind == PaperKind.Custom)
{
_Devmode.dmPaperWidth =
Convert.ToInt16 ((double)Math.Round (((Convert.ToDouble (pageSettings.PaperSize.Width))/100D)*25.4D*10D));
_Devmode.dmPaperLength =
Convert.ToInt16 ((double)Math.Round ((Convert.ToDouble (pageSettings.PaperSize.Height)/100D)*25.4D*10D));
}
_Devmode.dmDuplex = (short)duplex;
Marshal.StructureToPtr( _Devmode,_YDevModeData,true);
_pinfo.pDevMode = _YDevModeData;
_pinfo.pSecurityDescriptor = IntPtr.Zero;
/*update driver dependent part of the DEVMODE
1 = DocumentProperties(IntPtr.Zero, _hPrinter, sPrinterName, _YDevModeData
, ref _pinfo.pDevMode, (DM_IN_BUFFER | DM_OUT_BUFFER));*/
Marshal.StructureToPtr(_pinfo,_PtrPrinterInfo,true);
_LastError = Marshal.GetLastWin32Error();
_NRet = Convert.ToInt16(SetPrinter(_hPrinter, 2, _PtrPrinterInfo, 0));
if (_NRet == 0)
{
//Unable to set shared printer settings.
_LastError = Marshal.GetLastWin32Error();
//string myErrMsg = GetErrorMessage(_LastError);
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
finally
{
if (_hPrinter != IntPtr.Zero)
{
ClosePrinter(_hPrinter);
}
}
return Convert.ToBoolean(_NRet);
}
#endregion ChangePrinterSetting(string PrinterName,PageSettings pageSettings, bool landscape)
#region ChangePrinterSetting(string PrinterName,Duplex duplex)
public bool ChangePrinterSetting(string PrinterName,Duplex duplex)
{
try
{
_Devmode = this.GetPrinterSettings( PrinterName);
_Devmode.dmDuplex = (short)duplex;
Marshal.StructureToPtr( _Devmode,_YDevModeData,true);
_pinfo.pDevMode = _YDevModeData;
_pinfo.pSecurityDescriptor = IntPtr.Zero;
/*update driver dependent part of the DEVMODE
1 = DocumentProperties(IntPtr.Zero, _hPrinter, sPrinterName, _YDevModeData
, ref _pinfo.pDevMode, (DM_IN_BUFFER | DM_OUT_BUFFER));*/
Marshal.StructureToPtr(_pinfo,_PtrPrinterInfo,true);
_LastError = Marshal.GetLastWin32Error();
_NRet = Convert.ToInt16(SetPrinter(_hPrinter, 2, _PtrPrinterInfo, 0));
if (_NRet == 0)
{
//Unable to set shared printer settings.
_LastError = Marshal.GetLastWin32Error();
//string myErrMsg = GetErrorMessage(_LastError);
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
finally
{
if (_hPrinter != IntPtr.Zero)
{
ClosePrinter(_hPrinter);
}
}
return Convert.ToBoolean(_NRet);
}
#endregion ChangePrinterSetting(string PrinterName,Duplex duplex)
#region GetPrinterSettings(string PrinterName)
private DEVMODE GetPrinterSettings(string PrinterName)
{
DEVMODE devmode;
const int PRINTER_ACCESS_ADMINISTER = 0x4;
const int PRINTER_ACCESS_USE = 0x8;
const int PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE);
_PrinterValues.pDatatype =0;
_PrinterValues.pDevMode = 0 ;
_PrinterValues.DesiredAccess = PRINTER_ALL_ACCESS;
_NRet = Convert.ToInt32(OpenPrinter(PrinterName, out _hPrinter, ref _PrinterValues));
if (_NRet == 0)
{
_LastError = Marshal.GetLastWin32Error();
throw new Win32Exception(Marshal.GetLastWin32Error());
}
GetPrinter(_hPrinter, 2, IntPtr.Zero, 0, out _NBytesNeeded);
if (_NBytesNeeded <= 0)
{
throw new System.Exception("Unable to allocate memory");
}
else
{
// Allocate enough space for PRINTER_INFO_2... {ptrPrinterIn fo = Marshal.AllocCoTaskMem(_NBytesNeeded)};
_PtrPrinterInfo = Marshal.AllocHGlobal(_NBytesNeeded);
// The second GetPrinter fills in all the current settings, so all you // need to do is modify what you're interested in...
_NRet = Convert.ToInt32(GetPrinter(_hPrinter, 2, _PtrPrinterInfo, _NBytesNeeded, out _NJunk));
if (_NRet == 0)
{
_LastError = Marshal.GetLastWin32Error();
throw new Win32Exception(Marshal.GetLastWin32Error());
}
_pinfo = (PRINTER_INFO_2)Marshal.PtrToStructure(_PtrPrinterInfo, typeof(PRINTER_INFO_2));
IntPtr Temp = new IntPtr();
if (_pinfo.pDevMode == IntPtr.Zero)
{
// If GetPrinter didn't fill in the DEVMODE, try to get it by calling
// DocumentProperties...
IntPtr ptrZero = IntPtr.Zero;
//get the size of the devmode structure
_SizeOfDevMode = DocumentProperties(IntPtr.Zero, _hPrinter, PrinterName, ptrZero, ref ptrZero, 0);
_PtrDM = Marshal.AllocCoTaskMem(_SizeOfDevMode);
int i ;
i = DocumentProperties(IntPtr.Zero, _hPrinter, PrinterName, _PtrDM, ref ptrZero, DM_OUT_BUFFER);
if ((i < 0) || (_PtrDM == IntPtr.Zero))
{
//Cannot get the DEVMODE structure.
throw new System.Exception("Cannot get DEVMODE data");
}
_pinfo.pDevMode = _PtrDM;
}
_IntError = DocumentProperties(IntPtr.Zero, _hPrinter, PrinterName, IntPtr.Zero , ref Temp , 0);
//IntPtr _YDevModeData = Marshal.AllocCoTaskMem(i1);
_YDevModeData= Marshal.AllocHGlobal(_IntError);
_IntError = DocumentProperties(IntPtr.Zero, _hPrinter, PrinterName, _YDevModeData , ref Temp , 2);
devmode = (DEVMODE)Marshal.PtrToStructure(_YDevModeData, typeof(DEVMODE));
//_NRet = DocumentProperties(IntPtr.Zero, _hPrinter, sPrinterName, _YDevModeData
// , ref _YDevModeData, (DM_IN_BUFFER | DM_OUT_BUFFER));
if ((_NRet == 0) || (_hPrinter == IntPtr.Zero))
{
_LastError = Marshal.GetLastWin32Error();
throw new Win32Exception(Marshal.GetLastWin32Error());
}
return devmode;
}
}
#endregion GetPrinterSettings(string PrinterName)
#endregion "Function to change printer settings"
}
#endregion PrinterConfiguration
}
|
|
|
|
|
Your alternative to the codes in the thread is quite helpful. But I wonder on how to code to set the dmFormName of DEVMODE structure and use the custom size form as the current form for the Device Context (DC) of the printer without changing current default setting of the printer in C#. Can you give me some hints on that?
Thank you.
|
|
|
|
|
Thanks for this. I wanted some code to change the default paper bin of a printer (so I could get Word to use it). After scouring the internet for a solution I finally came across this article and then your modifications.
I had this code working in minutes.
|
|
|
|
|
Hi,
I'm trying to get the status of the printer; offline, ready, etc. I've used the code in this article to implement a call to GetPrinter, but when i examine the contents of the PRINTER_INFO_2 struct after making the call, all the strings are empty and all the int values are 0. Could anyone shed some light on this problem?
Thanks
|
|
|
|
|
Hi,
GetPrint() works for me, it returns portName, job count, ...
But it always gives status=0 !
Reason is:
http://support.microsoft.com/kb/160129[^]
says:
There is one fundamental premise that must be true to determine the state of a physical printer: the Spooler must be attempting to send a print job to the physical printer. This is the only time the state of the printer is reported by the port monitor.
-- modified at 16:55 Tuesday 30th January, 2007
Luc Pattyn
|
|
|
|
|