当前位置: 代码迷 >> 综合 >> API(12)——打印系统开发(51)——C#:调用API函数,弹出对话框更改打印机默认设置
  详细解决方案

API(12)——打印系统开发(51)——C#:调用API函数,弹出对话框更改打印机默认设置

热度:64   发布时间:2023-10-01 14:23:31.0

虽然说.NET为我们提供了很多打印设置的功能,比如PrintDialog。

可是有的功能是没有实现的,比如PrintDialog的窗体中,按下“打印机”后,弹出来的打印机设置窗口。

会发现,这个打印机设置会根据不同的打印机而不同。

而它更改的,是打印机的默认设置。

 

怎么实现这个功能呢?

这个难题让我在网上寻觅了一个星期。

也没有找到实现这个功能的代码。

要么就是只能弹出这个对话框,不能保存修改。

要么就是只能直接修改设置,不能弹出对话框。

 

经过一番摸索和尝试。我终于得出了以下的一个类。调用这个类唯一的公共方法,ChangePrinterSetting(string PrinterName),即可以修改相应名字的打印机默认设置。VS2005下调试通过。希望对需要的朋友有所帮助。

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.ComponentModel;
namespace PrinterSetting
{//written by fujiepublic class PrinterSetting{[StructLayout(LayoutKind.Sequential)]public struct PRINTER_DEFAULTS{public int pDatatype;public int pDevMode;public int DesiredAccess;}[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;}[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;}#region ■变量_____________________________________________________________private IntPtr hPrinter = new System.IntPtr();private PRINTER_DEFAULTS PrinterValues = new PRINTER_DEFAULTS();private PRINTER_INFO_2 pinfo = new PRINTER_INFO_2();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 ■API___________________________________________________________[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, IntPtrpPrinter, int Command);#endregion#region ■常数_____________________________________________________________private const int DM_OUT_BUFFER = 2;private const int STANDARD_RIGHTS_REQUIRED = 0xF0000;private const int PRINTER_ACCESS_ADMINISTER = 0x4;private const int PRINTER_ACCESS_USE = 0x8;private const int PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE);#endregion#region ■方法_____________________________________________________________public void ChangePrinterSetting(string i_printerName){DEVMODE dm;IntPtr pPrinter = IntPtr.Zero;IntPtr pDevModeOutput = IntPtr.Zero;IntPtr pDevModeInput = IntPtr.Zero;PrinterValues.pDatatype = 0;PrinterValues.pDevMode = 0;PrinterValues.DesiredAccess = PRINTER_ALL_ACCESS;OpenPrinter(i_printerName, out pPrinter, ref PrinterValues);int iNeeded = DocumentProperties(IntPtr.Zero, pPrinter, i_printerName, pDevModeOutput, ref pDevModeInput, 0);pDevModeOutput = Marshal.AllocHGlobal(iNeeded);int mode = 2 | 4;int nRet = DocumentProperties(IntPtr.Zero, pPrinter, i_printerName, pDevModeOutput, ref pDevModeInput, mode);if (nRet == 1){dm = (DEVMODE)Marshal.PtrToStructure(pDevModeOutput, typeof(DEVMODE));ChangePrinterSetting(i_printerName, ref dm);}ClosePrinter(pPrinter);}private void ChangePrinterSetting(string i_printerName, ref DEVMODE i_fujie){{dm = this.GetPrinterSettings(i_printerName);dm = i_fujie;Marshal.StructureToPtr(dm, 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){lastError = Marshal.GetLastWin32Error();throw new Win32Exception(Marshal.GetLastWin32Error());}if (hPrinter != IntPtr.Zero)ClosePrinter(hPrinter);}}private DEVMODE GetPrinterSettings(string i_printerName){DEVMODE dm;nRet = Convert.ToInt32(OpenPrinter(i_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 by fujie");}else{ptrPrinterInfo = Marshal.AllocHGlobal(nBytesNeeded);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){IntPtr ptrZero = IntPtr.Zero;sizeOfDevMode = DocumentProperties(IntPtr.Zero, hPrinter, i_printerName, ptrZero, ref ptrZero, 0);ptrDM = Marshal.AllocCoTaskMem(sizeOfDevMode);int i;i = DocumentProperties(IntPtr.Zero, hPrinter, i_printerName, ptrDM, ref ptrZero, DM_OUT_BUFFER);if ((i < 0) || (ptrDM == IntPtr.Zero)){throw new System.Exception("fujie:Cannot get DEVMODE data");}pinfo.pDevMode = ptrDM;}intError = DocumentProperties(IntPtr.Zero, hPrinter, i_printerName, IntPtr.Zero, ref Temp, 0);yDevModeData = Marshal.AllocHGlobal(intError);intError = DocumentProperties(IntPtr.Zero, hPrinter, i_printerName, yDevModeData, ref Temp, 2);dm = (DEVMODE)Marshal.PtrToStructure(yDevModeData, typeof(DEVMODE));if ((nRet == 0) || (hPrinter == IntPtr.Zero)){lastError = Marshal.GetLastWin32Error();throw new Win32Exception(Marshal.GetLastWin32Error());}return dm;}}#endregion}
}

经典评论:

1、没打印机呀。

2、我用的是局域网的打印机,属性窗口也能出来,但是,无论我改变还是不改变打印设置,点击确定或取消,我的程序就从运行退出来了,我还以为是我没有权限去改变所连接的机子的打印机默认设置,所以我装了一个虚拟打印机,但是还是没能成功,麻烦你给看看什么问题吧。

3、第142行,为什么要把mode给赋成2|4这个值?这个值是6,为什么呢?

4、我调试时,每次到了143行这就出现问题,nRet这个值老是不是1。

5、我在VS2008下编译这段程序,但总是在159行的时候整个程序就崩溃了,不论我是否修改pinfo,请问您有碰到类似情况么?

6、修改不成功,看不出哪里有问题啊,兄弟指点一下呗,好像全部语句都执行了。

7、为何设置后点击确认,程序会直接挂掉,还有就是选择Fax时会出现异常。

8、仔细在看了一下,发现只能修改页面设置的内容,其他页面的属性修改不了。

9、楼主,只能设置基本的页面,页数等,对一些打印机不能设置双面打印,设置成功,但是双面设置没有变化,通过调试看DEVMODER的dmDuplex已变化 ,但设置后,实际无变化,求解!