繁体   English   中英

C#.NET Frameork 3.5:打印pdf时在运行时更改打印机设置

[英]C# .NET Frameork 3.5: Change printer setting at run time while printing pdf

我正在使用VS2010。 .NET Framework 3.5。

前提条件:

  1. 系统上未安装Adobe。

  2. 不使用第三方dll

  3. 应该使用Windows dll。

到目前为止,我可以打印pdf文件,但无法在运行时更改打印机设置。

打印pdf文件的基本思想是,我读取了pdf文件的字节并将其直接发送给打印机。 在这里,它会打印pdf文件,没有任何问题。

但是文件在页面上并排打印,但是我希望它仅打印页面的一侧而不是双面。 为此,我试图在运行时更改打印机设置。

我已经在两台不同的打印机上测试了我的代码。 在一台打印机上,它是在同一页上并排打印,而在另一台打印机上,是在一页上。 这意味着打印机设置不会更改。

代码如下所示。 使用了4类:

//Class 1: This class basically tries to change the printer setting at run time

 public class PrinterSettingForPdf

{

 #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 PRINTER_INFO_9 pinfo9 = new PRINTER_INFO_9();

 private DEVMODE dm;

 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 "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 "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 "Data structure"

 [StructLayout(LayoutKind.Sequential)]

 public struct PRINTER_DEFAULTS

{

 public int pDatatype;

 public int pDevMode;

 public int DesiredAccess;

}

 [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;

}

 /// <summary>

 /// The PRINTER_INFO_9 structure specifies the per-user default printer settings.

 /// </summary>

 /// <seealso href="http://msdn.microsoft.com/en-us/library/windows/desktop/dd162852(v=vs.85).aspx"/>

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]

 internal class PRINTER_INFO_9

{

 /// <summary>

 /// A pointer to a DEVMODE structure that defines the per-user

 /// default printer data such as the paper orientation and the resolution.

 /// The DEVMODE is stored in the user's registry.

 /// </summary>

 public IntPtr pDevMode;

}

 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;

}

#endregion

 #region "Function to change printer settings"


 public bool ChangePrintersetting(string sPrinterName, PrinterData pd, int numbeOfCopies, bool preserverOldSettings)

{

 if (((int)pd.Duplex < 1) || ((int)pd.Duplex > 3))

{

 throw new ArgumentOutOfRangeException("nDuplexSetting", "nDup lexSetting is incorrect.");

}

 else

{

 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);

 //const int READ_CONTROL = 0x20000;

 //const int PRINTER_NORMAL_ACCESS = 131080; // (READ_CONTROL | PRINTER_ACCESS_USE);

PrinterValues.pDatatype = 0;

PrinterValues.pDevMode = 0;

PrinterValues.DesiredAccess = PRINTER_ALL_ACCESS;

 nRet = Convert.ToInt32(OpenPrinter(sPrinterName, 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)

{

 return false;

}

 // 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, 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();

 int i1 = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, IntPtr.Zero, ref Temp, 0);

 //IntPtr yDevModeData = Marshal.AllocCoTaskMem(i1);

 IntPtr yDevModeData = Marshal.AllocHGlobal(i1);

 i1 = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, yDevModeData, ref Temp, 2);

 dm = (DEVMODE)Marshal.PtrToStructure(yDevModeData, typeof(DEVMODE));

 dm.dmDefaultSource = (short)pd.Source;

 dm.dmOrientation = (short)pd.Orientation;

 dm.dmPaperSize = (short)pd.Size;

 dm.dmCopies = (short)1;

 dm.dmDuplex = (short)pd.Duplex;

 Marshal.StructureToPtr(dm, yDevModeData, true);

 //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());

}

 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, sPrinterName, ptrZero, ref ptrZero, 0);

 if (nRet <= 0)

{

 return false;

}

 ptrDM = Marshal.AllocCoTaskMem(sizeOfDevMode);

 int i;

 i = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, ptrDM,

 ref ptrZero, DM_OUT_BUFFER);

 if ((i < 0) || (ptrDM == IntPtr.Zero))

{

 //Cannot get the DEVMODE structure.

 return false;

}

pinfo.pDevMode = ptrDM;

}

 if (!Convert.ToBoolean(dm.dmFields & DM_DUPLEX))

{

 //You cannot modify the duplex flag for this printer

 //because it does not support duplex or the driver does not support setting

 //it from the Windows API.

 //return false;

}

pinfo.pDevMode = yDevModeData;

 pinfo.pSecurityDescriptor = IntPtr.Zero;

 /*update driver dependent part of the DEVMODE

i1 = DocumentProperties(IntPtr.Zero, hPrinter, sPrinterName, yDevModeData

, ref pinfo.pDevMode, (DM_IN_BUFFER | DM_OUT_BUFFER));*/

 if (i1 < 0)

{

 //Unable to set duplex setting to this printer.

 return false;

}

 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());

}

 return Convert.ToBoolean(nRet);

}

}

#endregion

}


//Class 2: Supporting Printer setting class

public class PrinterData

{

 public int Duplex { get; set; }

 public int Source { get; set; }

 public int Orientation { get; set; }

 public int Size { get; set; }

}


//Class 3: This class uses Windows dlls methods to print pdf contents

public class PrintPdf

{

 // Structure and API declarions:

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]

 public class DOCINFOA

{

 [MarshalAs(UnmanagedType.LPStr)]

 public string pDocName;

 [MarshalAs(UnmanagedType.LPStr)]

 public string pOutputFile;

 [MarshalAs(UnmanagedType.LPStr)]

 public string pDataType;

}

 [DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]

 public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);

 [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]

 public static extern bool ClosePrinter(IntPtr hPrinter);

 [DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]

 public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);

 [DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]

 public static extern bool EndDocPrinter(IntPtr hPrinter);

 [DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]

 public static extern bool StartPagePrinter(IntPtr hPrinter);

 [DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]

 public static extern bool EndPagePrinter(IntPtr hPrinter);

 [DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]

 public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);

 

 // SendBytesToPrinter()

 // When the function is given a printer name and an unmanaged array

 // of bytes, the function sends those bytes to the print queue.

 // Returns true on success, false on failure.

 public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)

{

 Int32 dwError = 0, dwWritten = 0;

 IntPtr hPrinter = new IntPtr(0);

 DOCINFOA di = new DOCINFOA();

 bool bSuccess = false; // Assume failure unless you specifically succeed.

 di.pDocName = "My C#.NET RAW Document";

 di.pDataType = "RAW";

 // Open the printer.

 //if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))

 PrinterSettingForPdf objPS = new PrinterSettingForPdf();

 PrinterData objPD = new PrinterData();

objPD.Duplex = 1;

objPD.Orientation = 1;

 //objPD.Size = 1;

 //objPD.Source = 1;

 

 if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))

{

 // Start a document.

 if (StartDocPrinter(hPrinter, 1, di))

{

 // Start a page.

 if (StartPagePrinter(hPrinter))

{

 objPS.ChangePrintersetting(szPrinterName, objPD, 1, false);

 // Write your bytes.

 bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);

EndPagePrinter(hPrinter);

}

EndDocPrinter(hPrinter);

}

 if (hPrinter != IntPtr.Zero)

ClosePrinter(hPrinter);

 // ClosePrinter(hPrinter);

}

 // If you did not succeed, GetLastError may give more information

 // about why not.

 if (bSuccess == false)

{

 dwError = Marshal.GetLastWin32Error();

}

 return bSuccess;

}

 public static bool SendFileToPrinter(string szPrinterName, string szFileName)

{

 // Open the file.

 FileStream fs = new FileStream(szFileName, FileMode.Open);

 // Create a BinaryReader on the file.

 BinaryReader br = new BinaryReader(fs);

 // Dim an array of bytes big enough to hold the file's contents.

 Byte[] bytes = new Byte[fs.Length];

 bool bSuccess = false;

 // Your unmanaged pointer.

 IntPtr pUnmanagedBytes = new IntPtr(0);

 int nLength;

 nLength = Convert.ToInt32(fs.Length);

 // Read the contents of the file into the array.

bytes = br.ReadBytes(nLength);

 // Allocate some unmanaged memory for those bytes.

 pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength);

 // Copy the managed byte array into the unmanaged array.

 Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength);

 // Send the unmanaged bytes to the printer.

bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength);

 // Free the unmanaged memory that you allocated earlier.

 Marshal.FreeCoTaskMem(pUnmanagedBytes);

 return bSuccess;

}

 public static bool SendStringToPrinter(string szPrinterName, string szString)

{

 IntPtr pBytes;

 Int32 dwCount;

 // How many characters are in the string?

dwCount = szString.Length;

 // Assume that the printer is expecting ANSI text, and then convert

 // the string to ANSI text.

 pBytes = Marshal.StringToCoTaskMemAnsi(szString);

 // Send the converted ANSI string to the printer.

SendBytesToPrinter(szPrinterName, pBytes, dwCount);

 Marshal.FreeCoTaskMem(pBytes);

 return true;

}

}


//Class 4: Class that handles printing pdf

public class PrintingPDFData

{

public void SilentPrintPdf(string PdfFileName, string PrinterName)

{

 try

{

 PrintPdf.SendFileToPrinter(PrinterName, PdfFileName);

}

 catch (Exception ex)

{

}

}

}

如果需要进一步说明,请告诉我。

提前致谢。

我相信使用Win32 Winspool API打印高级文档时,如果我正确解释了文档,则设备模式设置将不可用。 根据MSDN:

当在StartDocPrinter调用的pDocInfo参数中传递的DOC_INFO_1结构的pDatatype成员的值是“ RAW”时,将不使用pDefault参数的PRINTER_DEFAULTS结构中定义的DEVMODE设置。 当高级文档(如Adobe PDF或Microsoft Word文件)或其他打印机数据(如PCL,PS或HPGL)直接发送到pDatatype设置为“ RAW”的打印机时, 该文档必须完整描述DEVMODE样式的打印作业设置,使用硬件可以理解的语言

https://msdn.microsoft.com/en-us/library/windows/desktop/dd162751%28v=vs.85%29.aspx

您正在使用“ RAW”将PDF字节发送到打印机,这是此处描述的方案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM