以下代码参考了蜡纸张等人的作品,在此一并感谢!
using System;
using System.Text;
using System.Security;
using System.ComponentModel;
using System.Runtime.InteropServices;
/// <summary>
/// 改變打印機的設置
/// </summary>
public class Printer
{
#region "Private Variables"
private static IntPtr hPrinter = new System.IntPtr() ;
private static PRINTER_DEFAULTS pd = new PRINTER_DEFAULTS();
private static PRINTER_INFO_2 pinfo = new PRINTER_INFO_2();
private static DEVMODE dm;
private static IntPtr ptrDM;
private static IntPtr ptrPrinterInfo;
private static IntPtr hDummy;
private static int sizeOfDevMode = 0;
private static int lastError;
private static int nBytesNeeded;
// private static int hPrinterInfoSize,iDummyInt;
private static int nRet;//long
private static int intError;
private static System.Int32 nJunk;
private static IntPtr yDevModeData;
#endregion
#region "API Define"
[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 = "DocumentPropertiesA", SetLastError = true,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
internal static extern int DocumentProperties(
IntPtr hwnd,
IntPtr hPrinter,
[MarshalAs(UnmanagedType.LPStr)] string pDeviceName,
IntPtr pDevModeOutput,
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);
[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern bool GetDefaultPrinter(StringBuilder pszBuffer, ref int size);
[DllImport("GDI32.dll", EntryPoint = "CreateDC", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = false,
CallingConvention = CallingConvention.StdCall),
SuppressUnmanagedCodeSecurityAttribute()]
internal static extern IntPtr CreateDC([MarshalAs(UnmanagedType.LPTStr)]
string pDrive,
[MarshalAs(UnmanagedType.LPTStr)] string pName,
[MarshalAs(UnmanagedType.LPTStr)] string pOutput,
ref DEVMODE pDevMode);
[DllImport("GDI32.dll", EntryPoint = "ResetDC", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = false,
CallingConvention = CallingConvention.StdCall),
SuppressUnmanagedCodeSecurityAttribute()]
internal static extern IntPtr ResetDC(
IntPtr hDC,
ref DEVMODE
pDevMode);
[DllImport("GDI32.dll", EntryPoint = "DeleteDC", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = false,
CallingConvention = CallingConvention.StdCall),
SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool DeleteDC(IntPtr hDC);
[DllImport("winspool.drv", EntryPoint="DeviceCapabilitiesA", SetLastError=true)]
internal static extern Int32 DeviceCapabilities(
[MarshalAs(UnmanagedType.LPStr)] String device,
[MarshalAs(UnmanagedType.LPStr)] String port,
Int16 capability,
IntPtr outputBuffer,
IntPtr deviceMode);
[DllImport("winspool.drv", SetLastError=true)]
internal static extern bool EnumPrintersW(Int32 flags,
[MarshalAs(UnmanagedType.LPTStr)] string printerName,
Int32 level, IntPtr buffer, Int32 bufferSize, out Int32
requiredBufferSize, out Int32 numPrintersReturned);
[DllImport("kernel32.dll", EntryPoint="GetLastError", SetLastError=false,
ExactSpelling=true, CallingConvention=CallingConvention.StdCall),
SuppressUnmanagedCodeSecurityAttribute()]
internal static extern Int32 GetLastError();
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(
IntPtr windowHandle,
uint Msg,
IntPtr wParam,
IntPtr lParam,
SendMessageTimeoutFlags flags,
uint timeout,
out IntPtr result
);
#endregion
#region "Data structure"
/// <summary>
/// 紙張訪問權限等信息
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_DEFAULTS
{
public int pDatatype;
public int pDevMode;
public int DesiredAccess;//對打印機的訪問權限
}
//紙張方向
public enum PageOrientation
{
DMORIENT_PORTRAIT =1,//豎向
DMORIENT_LANDSCAPE =2,//橫向
}
/// <summary>
/// 紙張類型
/// </summary>
public enum PaperSize
{
DMPAPER_LETTER = 1, // Letter 8 1/2 x 11 in
DMPAPER_LETTERSMALL = 2, // Letter Small 8 1/2 x 11 in
DMPAPER_TABLOID = 3, // Tabloid 11 x 17 in
DMPAPER_LEDGER = 4, // Ledger 17 x 11 in
DMPAPER_LEGAL = 5, // Legal 8 1/2 x 14 in
DMPAPER_STATEMENT = 6, // Statement 5 1/2 x 8 1/2 in
DMPAPER_EXECUTIVE = 7, // Executive 7 1/4 x 10 1/2 in
DMPAPER_A3 = 8, // A3 297 x 420 mm
DMPAPER_A4 = 9, // A4 210 x 297 mm
DMPAPER_A4SMALL = 10, // A4 Small 210 x 297 mm
DMPAPER_A5 = 11, // A5 148 x 210 mm
DMPAPER_B4 = 12, // B4 250 x 354
DMPAPER_B5 = 13, // B5 182 x 257 mm
DMPAPER_FOLIO = 14, // Folio 8 1/2 x 13 in
DMPAPER_QUARTO = 15, // Quarto 215 x 275 mm
DMPAPER_10X14 = 16, // 10x14 in
DMPAPER_11X17 = 17, // 11x17 in
DMPAPER_NOTE = 18, // Note 8 1/2 x 11 in
DMPAPER_ENV_9 = 19, // Envelope #9 3 7/8 x 8 7/8
DMPAPER_ENV_10 = 20, // Envelope #10 4 1/8 x 9 1/2
DMPAPER_ENV_11 = 21, // Envelope #11 4 1/2 x 10 3/8
DMPAPER_ENV_12 = 22, // Envelope #12 4 /276 x 11
DMPAPER_ENV_14 = 23, // Envelope #14 5 x 11 1/2
DMPAPER_CSHEET = 24, // C size sheet
DMPAPER_DSHEET = 25, // D size sheet
DMPAPER_ESHEET = 26, // E size sheet
DMPAPER_ENV_DL = 27, // Envelope DL 110 x 220mm
DMPAPER_ENV_C5 = 28, // Envelope C5 162 x 229 mm
DMPAPER_ENV_C3 = 29, // Envelope C3 324 x 458 mm
DMPAPER_ENV_C4 = 30, // Envelope C4 229 x 324 mm
DMPAPER_ENV_C6 = 31, // Envelope C6 114 x 162 mm
DMPAPER_ENV_C65 = 32, // Envelope C65 114 x 229 mm
DMPAPER_ENV_B4 = 33, // Envelope B4 250 x 353 mm
DMPAPER_ENV_B5 = 34, // Envelope B5 176 x 250 mm
DMPAPER_ENV_B6 = 35, // Envelope B6 176 x 125 mm
DMPAPER_ENV_ITALY = 36, // Envelope 110 x 230 mm
DMPAPER_ENV_MONARCH = 37, // Envelope Monarch 3.875 x 7.5 in
DMPAPER_ENV_PERSONAL = 38, // 6 3/4 Envelope 3 5/8 x 6 1/2 in
DMPAPER_FANFOLD_US = 39, // US Std Fanfold 14 7/8 x 11 in
DMPAPER_FANFOLD_STD_GERMAN = 40 , // German Std Fanfold 8 1/2 x 12 in
DMPAPER_FANFOLD_LGL_GERMAN = 41, // German Legal Fanfold 8 1/2 x 13 in
DMPAPER_USER = 256,// user defined
DMPAPER_FIRST = DMPAPER_LETTER,
DMPAPER_LAST = DMPAPER_USER,
}
/// <summary>
/// 紙張來源
/// </summary>
public enum PaperSource
{
DMBIN_UPPER = 1,
DMBIN_LOWER = 2,
DMBIN_MIDDLE = 3,
DMBIN_MANUAL = 4,
DMBIN_ENVELOPE = 5,
DMBIN_ENVMANUAL = 6,
DMBIN_AUTO = 7,
DMBIN_TRACTOR = 8,
DMBIN_SMALLFMT = 9,
DMBIN_LARGEFMT = 10,
DMBIN_LARGECAPACITY = 11,
DMBIN_CASSETTE = 14,
DMBIN_FORMSOURCE = 15,
DMRES_DRAFT = -1,
DMRES_LOW = -2,
DMRES_MEDIUM = -3,
DMRES_HIGH = -4
}
/// <summary>
/// 是否要雙面打印
/// </summary>
public enum PageDuplex
{
DMDUP_HORIZONTAL = 3,
DMDUP_SIMPLEX = 1,
DMDUP_VERTICAL = 2
}
/// <summary>
/// 需設置的打印信息
/// </summary>
public struct PrinterData
{
public PageOrientation Orientation;//打印方向
public PaperSize Size;//打印紙張類型(用數字表示 256為用戶自定紙張)
public PaperSource source;//紙張來源
public PageDuplex Duplex;//是否雙面列印等信息
public int pLength;//紙張的高
public int pWidth;//紙張的寬
public int pmFields;//需改變的信息進行"|"運算後的和
public string pFormName;//紙張的名字
}
//打印機信息 2 打印機信息結構包含1-9個級別,詳細信息請參考API
[StructLayout(LayoutKind.Sequential)]
private 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;
}
//打印機信息 5 打印機信息結構包含1-9個級別,詳細信息請參考API
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
private struct PRINTER_INFO_5
{
[MarshalAs(UnmanagedType.LPTStr)] public String PrinterName;
[MarshalAs(UnmanagedType.LPTStr)] public String PortName;
[MarshalAs(UnmanagedType.U4)] public Int32 Attributes;
[MarshalAs(UnmanagedType.U4)] public Int32 DeviceNotSelectedTimeout;
[MarshalAs(UnmanagedType.U4)] public Int32 TransmissionRetryTimeout;
}
//打印機信息 9 打印機信息結構包含1-9個級別,詳細信息請參考API
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
internal struct PRINTER_INFO_9
{
public IntPtr pDevMode;
}
/// <summary>
/// The DEVMODE data structure contains information about the initialization and environment of a printer or a display device
///DEVMODE結構包含了打印機(或顯示設置)的初始化和當前狀態信息,詳細信息請參考API
/// </summary>
private const short CCDEVICENAME = 32;
private const short CCFORMNAME = 32;
[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCDEVICENAME)]
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 = CCFORMNAME)]
public string dmFormName;
public short dmUnusedPadding;
public short dmBitsPerPel;
public int dmPelsWidth;
public int dmPelsHeight;
public int dmDisplayFlags;
public int dmDisplayFrequency;
}
//SendMessageTimeout Flags
[Flags] public enum SendMessageTimeoutFlags : uint
{
SMTO_NORMAL = 0x0000,
SMTO_BLOCK = 0x0001,
SMTO_ABORTIFHUNG = 0x0002,
SMTO_NOTIMEOUTIFNOTHUNG = 0x0008
}
#endregion
#region "const Variables"
//DEVMODE.dmFields
const int DM_FORMNAME = 0x10000;//改變紙張名稱時需在dmFields設置此常量
const int DM_PAPERSIZE = 0x0002;//改變紙張類型時需在dmFields設置此常量
const int DM_PAPERLENGTH = 0x0004;//改變紙張長度時需在dmFields設置此常量
const int DM_PAPERWIDTH = 0x0008;//改變紙張寬度時需在dmFields設置此常量
const int DM_DUPLEX = 0x1000;//改變紙張是否雙面列印時需在dmFields設置此常量
const int DM_ORIENTATION = 0x0001;//改變紙張方向時需在dmFields設置此常量
//用於改變DocumentProperties的參數,詳細信息請參考API
const int DM_IN_BUFFER = 8;
const int DM_OUT_BUFFER = 2;
//用於設置對打印機的訪問權限
const int PRINTER_ACCESS_ADMINISTER = 0x4;
const int PRINTER_ACCESS_USE = 0x8;
const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
const int PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE);
//得到指定打印的所有紙張
const int PRINTER_ENUM_LOCAL = 2;
const int PRINTER_ENUM_CONNECTIONS = 4;
const int DC_PAPERNAMES = 16;
const int DC_PAPERS = 2;
const int DC_PAPERSIZE = 3;
//sendMessageTimeOut
const int WM_SETTINGCHANGE = 0x001A;
const int HWND_BROADCAST = 0xffff;
#endregion
#region printer method
/// <summary>
/// 獲取指定打印機的設置信息
/// </summary>
/// <param name="PrinterName">打印機的名字</param>
/// <returns>指定打印機的設置信息</returns>
private static DEVMODE GetPrinterDemode(string PrinterName)
{
DEVMODE dm;
pd.pDatatype =0;
pd.pDevMode = 0 ;
pd.DesiredAccess = PRINTER_ALL_ACCESS;
if(PrinterName ==string.Empty || PrinterName == null)
{
PrinterName = GetDeaultPrinterName();
}
nRet = Convert.ToInt32(OpenPrinter(PrinterName,out hPrinter, ref pd));
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, IntPtr.Zero, IntPtr.Zero, 0);
ptrDM = Marshal.AllocCoTaskMem(sizeOfDevMode);
int i ;
i = DocumentProperties(IntPtr.Zero, hPrinter, PrinterName, ptrDM,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 , Temp , 0);
//IntPtr yDevModeData = Marshal.AllocCoTaskMem(i1);
yDevModeData= Marshal.AllocHGlobal(intError);
intError = DocumentProperties(IntPtr.Zero, hPrinter,PrinterName, yDevModeData , Temp , 2);
dm = (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();
//string myErrMsg = GetErrorMessage(lastError);
throw new Win32Exception(Marshal.GetLastWin32Error());
}
return dm;
}
}
/// <summary>
/// 判斷是否已經改變過默認打印機的紙張
/// </summary>
/// <param name="FormName">紙張名稱</param>
/// <param name="width">寬</param>
/// <param name="length">高</param>
/// <returns>如果Devmode結構已經與當前給的三個參數一樣,則沒有必要改變,返回ture.沒有改變過,則返回false</returns>
public static bool IsChange(string FormName,int width,int length)
{
dm = Printer.GetPrinterDemode(null);
if(FormName == dm.dmFormName && width == dm.dmPaperWidth && length == dm.dmPaperLength)
return true;
else
return false;
}
/// <summary>
/// 改變打印機的設置
/// </summary>
/// <param name="PrinterName">打印機的名字,如果為空,自動得到默認打印機的名字</param>
/// <param name="PS">需改變信息</param>
/// <returns>是否改變成功</returns>
public static bool ModifyPrintInfo(string PrinterName,ref PrinterData PS)
{
if ((((int)PS.Duplex < 0) || ((int)PS.Duplex > 3)))
{
throw new ArgumentOutOfRangeException("nDuplexSetting","nDuplexSetting is incorrect.");
}
else
{
if(PrinterName ==string.Empty || PrinterName == null)
{
PrinterName = GetDeaultPrinterName();
}
dm = GetPrinterDemode(PrinterName);
if((int)PS.Size != 0)//是否改變紙張類型
{
dm.dmPaperSize = (short)PS.Size;
dm.dmFields |= DM_PAPERSIZE;
}
if(PS.pWidth != 0)//是否改變紙張寬度
{
dm.dmPaperWidth = (short)PS.pWidth;
dm.dmFields |= DM_PAPERWIDTH;
}
if(PS.pLength != 0)//是否改變紙張高度
{
dm.dmPaperLength = (short)PS.pLength;
dm.dmFields |= DM_PAPERLENGTH;
}
if(PS.pFormName != null && PS.pFormName != string.Empty)//是否改變紙張名稱
{
dm.dmFormName = PS.pFormName;
dm.dmFields |= DM_FORMNAME;
}
if((int)PS.Orientation != 0)//是否改變紙張方向
{
dm.dmOrientation = (short)PS.Orientation;
dm.dmFields |= DM_ORIENTATION;
}
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)
{
lastError = Marshal.GetLastWin32Error();//Unable to set shared printer settings.
throw new Win32Exception(Marshal.GetLastWin32Error());
}
if (hPrinter != IntPtr.Zero)
ClosePrinter(hPrinter);
return Convert.ToBoolean(nRet);
}
}
/// <summary>
/// 改變打印機的設置
/// </summary>
/// <param name="PrinterName">打印機的名字,如果為空,自動得到默認打印機的名字</param>
/// <param name="PS">需改變信息</param>
/// <returns>是否改變成功</returns>
public static void ModifyPrintInfo1(string PrinterName,ref PrinterData PS)
{
if(PrinterName ==string.Empty || PrinterName == null)
{
PrinterName = GetDeaultPrinterName();
}
IntPtr hDC = CreateDC("WINSPOOL",PrinterName,null,ref dm);
if(hDC != IntPtr.Zero)
{
if((int)PS.Size != 0)//是否改變紙張類型
{
dm.dmPaperSize = (short)PS.Size;
dm.dmFields |= DM_PAPERSIZE;
}
if(PS.pWidth != 0)//是否改變紙張寬度
{
dm.dmPaperWidth = (short)PS.pWidth;
dm.dmFields |= DM_PAPERWIDTH;
}
if(PS.pLength != 0)//是否改變紙張高度
{
dm.dmPaperLength = (short)PS.pLength;
dm.dmFields |= DM_PAPERLENGTH;
}
if(PS.pFormName != null && PS.pFormName != string.Empty)//是否改變紙張名稱
{
dm.dmFormName = PS.pFormName;
dm.dmFields |= DM_FORMNAME;
}
if((int)PS.Orientation != 0)//是否改變紙張方向
{
dm.dmOrientation = (short)PS.Orientation;
dm.dmFields |= DM_ORIENTATION;
}
ResetDC(hDC,ref dm);
DeleteDC(hDC);
}
}
/// <summary>
/// 改變打印機的設置
/// </summary>
/// <param name="PrinterName">打印機的名字,如果為空,自動得到默認打印機的名字</param>
/// <param name="PS">需改變信息</param>
/// <returns>是否改變成功</returns>
public static void ModifyPrintInfo2(string PrinterName,ref PrinterData PS)
{
PRINTER_INFO_9 printerInfo;
printerInfo.pDevMode = IntPtr.Zero;
if(PrinterName ==string.Empty || PrinterName == null)
{
PrinterName = GetDeaultPrinterName();
}
pd.pDatatype = 0;
pd.pDevMode = 0;
pd.DesiredAccess = PRINTER_ALL_ACCESS;
if(OpenPrinter(PrinterName,out hPrinter,ref pd))
{
try
{
//得到結構體DEVMODE的大小
int iDevModeSize = DocumentProperties(IntPtr.Zero,hPrinter,PrinterName,IntPtr.Zero,IntPtr.Zero,0);
if(iDevModeSize <0)
throw new ApplicationException("Cannot get the size of the DEVMODE structure.");
//分配指向結構體DEVMODE的內存緩沖區
IntPtr hDevMode = Marshal.AllocCoTaskMem(iDevModeSize + 100);
//得到一個指向DEVMODE內存緩區的指針
nRet = DocumentProperties(IntPtr.Zero,hPrinter,PrinterName,hDevMode,IntPtr.Zero,DM_OUT_BUFFER);
if(nRet < 0)
throw new ApplicationException("Cannot get the size of the DEVMODE structure.");
//給dm賦值
dm = (DEVMODE)Marshal.PtrToStructure(hDevMode,dm.GetType());
if ((((int)PS.Duplex < 0) || ((int)PS.Duplex > 3)))
{
throw new ArgumentOutOfRangeException("nDuplexSetting","nDuplexSetting is incorrect.");
}
else
{
//更改printersetting
if((int)PS.Size != 0)//是否改變紙張類型
{
dm.dmPaperSize = (short)PS.Size;
dm.dmFields |= DM_PAPERSIZE;
}
if(PS.pWidth != 0)//是否改變紙張寬度
{
dm.dmPaperWidth = (short)PS.pWidth;
dm.dmFields |= DM_PAPERWIDTH;
}
if(PS.pLength != 0)//是否改變紙張高度
{
dm.dmPaperLength = (short)PS.pLength;
dm.dmFields |= DM_PAPERLENGTH;
}
if(PS.pFormName != null && PS.pFormName != string.Empty)//是否改變紙張名稱
{
dm.dmFormName = PS.pFormName;
dm.dmFields |= DM_FORMNAME;
}
if((int)PS.Orientation != 0)//是否改變紙張方向
{
dm.dmOrientation = (short)PS.Orientation;
dm.dmFields |= DM_ORIENTATION;
}
Marshal.StructureToPtr( dm,hDevMode,true);
// pinfo.pDevMode = hDevMode;
// 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); //寫入內存
//得到printer info的大小
nRet = DocumentProperties(IntPtr.Zero,hPrinter,PrinterName,printerInfo.pDevMode,printerInfo.pDevMode,DM_IN_BUFFER | DM_OUT_BUFFER);
if(nRet<0)
{
throw new ApplicationException("Unable to set the PrintSetting for this printer");
}
GetPrinter(hPrinter,9,IntPtr.Zero,0,out nBytesNeeded);
if(nBytesNeeded == 0 )
throw new ApplicationException("GetPrinter failed.Couldn't get the nBytesNeeded for shared PRINTER_INFO_9 structure");
//分配內存緩沖區大小
ptrPrinterInfo = Marshal.AllocCoTaskMem(nBytesNeeded);
bool bSuccess = GetPrinter(hPrinter,9,ptrPrinterInfo,nBytesNeeded,out nJunk);
if(!bSuccess)
throw new ApplicationException("GetPrinter failed.Couldn't get the nBytesNeeded for shared PRINTER_INFO_9 structure");
//賦值給printerInfo
printerInfo = (PRINTER_INFO_9)Marshal.PtrToStructure(ptrPrinterInfo,printerInfo.GetType());
printerInfo.pDevMode = hDevMode;
//獲取一個指向 PRINTER_INFO_9結構的指針
Marshal.StructureToPtr(printerInfo,ptrPrinterInfo,true);
//設置打印機
bSuccess = SetPrinter(hPrinter,9,ptrPrinterInfo,0);
if(!bSuccess)
throw new Win32Exception(Marshal.GetLastWin32Error(), "SetPrinter() failed.Couldn't set the printer settings");
Printer.SendMessageTimeout(new IntPtr(HWND_BROADCAST),WM_SETTINGCHANGE,IntPtr.Zero,IntPtr.Zero,Printer.SendMessageTimeoutFlags.SMTO_NORMAL,1000,out hDummy);
}
}
finally
{
ClosePrinter(hPrinter);
}
}
}
/// <summary>
/// 改變打印機的設置
/// </summary>
/// <param name="PrinterName">打印機的名字,如果為空,自動得到默認打印機的名字</param>
/// <param name="PS">需改變信息</param>
/// <returns>是否改變成功</returns>
public static bool ModifyPrintInfo3(string PrinterName,ref PrinterData PS)
{
pd.pDatatype =0;
pd.pDevMode = 0 ;
pd.DesiredAccess = PRINTER_ALL_ACCESS;
if(PrinterName ==string.Empty || PrinterName == null)
{
PrinterName = GetDeaultPrinterName();
}
nRet = Convert.ToInt32(OpenPrinter(PrinterName,out hPrinter, ref pd));
if (nRet == 0)
{
lastError = Marshal.GetLastWin32Error();
throw new Win32Exception(Marshal.GetLastWin32Error());
}
//調用GetPrinter來獲取PRINTER_INFO_2在內存的字節數
GetPrinter(hPrinter, 2, IntPtr.Zero, 0, out nBytesNeeded);
if (nBytesNeeded <= 0)
{
ClosePrinter(hPrinter);
return false;
}
//為PRINTER_INFO_2分配足夠的內存
ptrPrinterInfo = Marshal.AllocHGlobal(nBytesNeeded);
if(ptrPrinterInfo == IntPtr.Zero)
{
ClosePrinter(hPrinter);
return false;
}
//調用GetPrinter填充所的當前設定,也就是你所想改變的信息(ptrPrinterInfo中)
if(!GetPrinter(hPrinter,2,ptrPrinterInfo,nBytesNeeded,out nBytesNeeded))
{
Marshal.FreeHGlobal(ptrPrinterInfo);
ClosePrinter(hPrinter);
return false;
}
//把內存中指向PRINTER_INFO_2的指針轉化為PRINTER_INFO_2結構
//如果GetPrinter沒有得到DEVMODE結構,將嘗試調用DocumentProperties得到DEVMODE結構
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
nBytesNeeded = DocumentProperties(IntPtr.Zero, hPrinter,PrinterName, IntPtr.Zero, IntPtr.Zero, 0);
if(nBytesNeeded <= 0)
{
Marshal.FreeHGlobal(ptrPrinterInfo);
ClosePrinter(hPrinter);
return false;
}
ptrDM = Marshal.AllocCoTaskMem(nBytesNeeded);
int i ;
i = DocumentProperties(IntPtr.Zero, hPrinter, PrinterName, ptrDM,ptrZero, DM_OUT_BUFFER);
if ((i < 0) || (ptrDM == IntPtr.Zero))
{
//Cannot get the DEVMODE structure.
Marshal.FreeHGlobal(ptrDM);
ClosePrinter(ptrPrinterInfo);
return false;
}
pinfo.pDevMode = ptrDM;
}
dm = (DEVMODE)Marshal.PtrToStructure(pinfo.pDevMode,typeof(DEVMODE));
//修改打印機的設定信息
if ((((int)PS.Duplex < 0) || ((int)PS.Duplex > 3)))
{
throw new ArgumentOutOfRangeException("nDuplexSetting","nDuplexSetting is incorrect.");
}
else
{
if(PrinterName ==string.Empty || PrinterName == null)
{
PrinterName = GetDeaultPrinterName();
}
if((int)PS.Size != 0)//是否改變紙張類型
{
dm.dmPaperSize = (short)PS.Size;
dm.dmFields |= DM_PAPERSIZE;
}
if(PS.pWidth != 0)//是否改變紙張寬度
{
dm.dmPaperWidth = (short)PS.pWidth;
dm.dmFields |= DM_PAPERWIDTH;
}
if(PS.pLength != 0)//是否改變紙張高度
{
dm.dmPaperLength = (short)PS.pLength;
dm.dmFields |= DM_PAPERLENGTH;
}
if(PS.pFormName != null && PS.pFormName != string.Empty)//是否改變紙張名稱
{
dm.dmFormName = PS.pFormName;
dm.dmFields |= DM_FORMNAME;
}
if((int)PS.Orientation != 0)//是否改變紙張方向
{
dm.dmOrientation = (short)PS.Orientation;
dm.dmFields |= DM_ORIENTATION;
}
Marshal.StructureToPtr( dm,pinfo.pDevMode,true);
Marshal.StructureToPtr(pinfo,ptrPrinterInfo,true);
pinfo.pSecurityDescriptor = IntPtr.Zero;
//Make sure the driver_Dependent part of devmode is updated...
nRet = DocumentProperties(IntPtr.Zero,hPrinter,PrinterName,pinfo.pDevMode,pinfo.pDevMode,DM_IN_BUFFER|DM_OUT_BUFFER);
if(nRet<=0)
{
Marshal.FreeHGlobal(ptrPrinterInfo);
ClosePrinter(hPrinter);
return false;
}
//SetPrinter 更新打印機信息
if(!SetPrinter(hPrinter,2,ptrPrinterInfo,0))
{
Marshal.FreeHGlobal(ptrPrinterInfo);
ClosePrinter(hPrinter);
return false;
}
//通知其它應用程序,打印機信息已經更改
Printer.SendMessageTimeout(new IntPtr(HWND_BROADCAST),WM_SETTINGCHANGE,IntPtr.Zero,IntPtr.Zero,Printer.SendMessageTimeoutFlags.SMTO_NORMAL,1000,out hDummy);
//釋放
if(ptrPrinterInfo == IntPtr.Zero)
Marshal.FreeHGlobal(ptrPrinterInfo);
if(hPrinter == IntPtr.Zero)
Marshal.FreeHGlobal(hPrinter);
return true;
}
}
/// <summary>
/// 得到默認打印機的名字
/// </summary>
/// <returns>返回默認打印機的名字</returns>
public static string GetDeaultPrinterName()
{
StringBuilder dp = new StringBuilder(256);
int size = dp.Capacity;
if (GetDefaultPrinter(dp, ref size))
{
return dp.ToString();
}
else
{
return string.Empty;
}
}
/// <summary>
/// 得到紙張的kind,如果為0則錯誤
/// </summary>
/// <param name="printerName">打印機名字,如果空將獲取默認打印機名</param>
/// <param name="paperName">紙張名稱,一定要填</param>
/// <returns>kind</returns>
public static short GetOnePaper(string printerName,string paperName)
{
short kind = 0;
if(printerName == null || printerName == string.Empty)
printerName = GetDeaultPrinterName();
PRINTER_INFO_5 info5;
int requiredSize;
int numPrinters;
bool foundPrinter = EnumPrintersW(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
string.Empty, 5, IntPtr.Zero, 0, out requiredSize, out numPrinters);
int info5Size = requiredSize;
IntPtr info5Ptr = Marshal.AllocHGlobal(info5Size);
IntPtr buffer = IntPtr.Zero;
try
{
foundPrinter = EnumPrintersW(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
string.Empty, 5, info5Ptr, info5Size, out requiredSize, out numPrinters);
string port = null;
for (int i = 0; i < numPrinters; i++)
{
info5 = (PRINTER_INFO_5)Marshal.PtrToStructure(
(IntPtr)((i * Marshal.SizeOf(typeof(PRINTER_INFO_5))) + (int)info5Ptr),
typeof(PRINTER_INFO_5));
if (info5.PrinterName == printerName)
{
port = info5.PortName;
}
}
int numNames = DeviceCapabilities(printerName, port, DC_PAPERNAMES, IntPtr.Zero, IntPtr.Zero);
if (numNames < 0)
{
int errorCode = GetLastError();
Console.WriteLine("Number of names = {1}: {0}", errorCode, numNames);
return 0;
}
buffer = Marshal.AllocHGlobal(numNames * 64);
numNames = DeviceCapabilities(printerName, port, DC_PAPERNAMES, buffer, IntPtr.Zero);
if (numNames < 0)
{
int errorCode = GetLastError();
Console.WriteLine("Number of names = {1}: {0}", errorCode, numNames);
return 0;
}
string[] names = new string[numNames];
for (int i = 0; i < numNames; i++)
{
names[i] = Marshal.PtrToStringAnsi((IntPtr)((i * 64) + (int)buffer));
}
Marshal.FreeHGlobal(buffer);
buffer = IntPtr.Zero;
int numPapers = DeviceCapabilities(printerName, port, DC_PAPERS, IntPtr.Zero, IntPtr.Zero);
if (numPapers < 0)
{
Console.WriteLine("No papers");
return 0;
}
buffer = Marshal.AllocHGlobal(numPapers * 2);
numPapers = DeviceCapabilities(printerName, port, DC_PAPERS, buffer, IntPtr.Zero);
if (numPapers < 0)
{
Console.WriteLine("No papers");
return 0;
}
short[] kinds = new short[numPapers];
for (int i = 0; i < numPapers; i++)
{
kinds[i] = Marshal.ReadInt16(buffer, i * 2);
}
for(int i = 0; i < numPapers; i++)
{
// Console.WriteLine("Paper {0} : {1}", kinds[i], names[i]);
if(names[i] == paperName)
kind = kinds[i];
break;
}
}
finally
{
Marshal.FreeHGlobal(info5Ptr);
}
return kind;
}
//在輸出所有可以的紙張
public static void GetPapers(string printerName)
{
if(printerName == null || printerName == string.Empty)
printerName = GetDeaultPrinterName();
PRINTER_INFO_5 info5;
int requiredSize;
int numPrinters;
bool foundPrinter = EnumPrintersW(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
string.Empty, 5, IntPtr.Zero, 0, out requiredSize, out numPrinters);
int info5Size = requiredSize;
IntPtr info5Ptr = Marshal.AllocHGlobal(info5Size);
IntPtr buffer = IntPtr.Zero;
try
{
foundPrinter = EnumPrintersW(PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
string.Empty, 5, info5Ptr, info5Size, out requiredSize, out numPrinters);
string port = null;
for (int i = 0; i < numPrinters; i++)
{
info5 = (PRINTER_INFO_5)Marshal.PtrToStructure(
(IntPtr)((i * Marshal.SizeOf(typeof(PRINTER_INFO_5))) + (int)info5Ptr),
typeof(PRINTER_INFO_5));
if (info5.PrinterName == printerName)
{
port = info5.PortName;
}
}
int numNames = DeviceCapabilities(printerName, port, DC_PAPERNAMES, IntPtr.Zero, IntPtr.Zero);
if (numNames < 0)
{
int errorCode = GetLastError();
Console.WriteLine("Number of names = {1}: {0}", errorCode, numNames);
return;
}
buffer = Marshal.AllocHGlobal(numNames * 64);
numNames = DeviceCapabilities(printerName, port, DC_PAPERNAMES, buffer, IntPtr.Zero);
if (numNames < 0)
{
int errorCode = GetLastError();
Console.WriteLine("Number of names = {1}: {0}", errorCode, numNames);
return;
}
string[] names = new string[numNames];
for (int i = 0; i < numNames; i++)
{
names[i] = Marshal.PtrToStringAnsi((IntPtr)((i * 64) + (int)buffer));
}
Marshal.FreeHGlobal(buffer);
buffer = IntPtr.Zero;
int numPapers = DeviceCapabilities(printerName, port, DC_PAPERS, IntPtr.Zero, IntPtr.Zero);
if (numPapers < 0)
{
Console.WriteLine("No papers");
return;
}
buffer = Marshal.AllocHGlobal(numPapers * 2);
numPapers = DeviceCapabilities(printerName, port, DC_PAPERS, buffer, IntPtr.Zero);
if (numPapers < 0)
{
Console.WriteLine("No papers");
return;
}
short[] kinds = new short[numPapers];
for (int i = 0; i < numPapers; i++)
{
kinds[i] = Marshal.ReadInt16(buffer, i * 2);
}
for(int i = 0; i < numPapers; i++)
{
Console.WriteLine("Paper {0} : {1}", kinds[i], names[i]);
}
}
finally
{
Marshal.FreeHGlobal(info5Ptr);
}
}
#endregion
}
以下使用方法:
void SetPrinterAndPaperSize(string printerName,string PaperSize)
{
switch(Papersize)/根據自已需求添加
{
case "A4":
if(!Printer.IsChange("A4",2100,2970))
{
Printer.PrinterData pd = new ERP.Report.Printer.PrinterData();//
pd.Duplex = 0;//不設置是否雙面打印(不設置即按默認設置對待,以下類同)
pd.Orientation = 0;//不設置打印方向
pd.pFormName ="A4";//紙張名字
pd.pLength = 2970;//設置打印機的高度
pd.pWidth = 2100;//設置打印機的寬度
pd.Size = ERP.Report.Printer.PaperSize.DMPAPER_USER;//自定義紙張
ModifyPrintInfo3(printerName,ref pd);//更改打印機信息
}
break;
case "5.5 英吋 8 1/2 x 5 1/2 in":
if(!Printer.IsChange("5.5 英吋 8 1/2 x 5 1/2 in",2159,1397))
{
Printer.PrinterData pd = new ERP.Report.Printer.PrinterData();//
pd.Duplex = 0;//不設置是否雙面打印(不設置即按默認設置對待,以下類同)
pd.Orientation = 0;//不設置打印方向
//pd.pFormName ="5.5 英吋 8 1/2 x 5 1/2 in";//紙張名字8.5X5.5
pd.pFormName ="8.5X5.5";
pd.pLength = 1397;//設置打印機的高度
pd.pWidth = 2159;//設置打印機的寬度
pd.Size = ERP.Report.Printer.PaperSize.DMPAPER_USER;//自定義紙張
ModifyPrintInfo3(printerName,ref pd);//更改打印機信息
}
break;
default:
break;
}
}