65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 C# 更改打印机设置

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.67/5 (36投票s)

2004年4月30日

CPOL

1分钟阅读

viewsIcon

469782

downloadIcon

5

使用 C# 修改打印机设置。

引言

我正在进行一个从 VB6 迁移到 C# 的项目。我有一个需求是为应用程序打印 MS Word 文档,并且应该给用户一个选项来更改要打印的文档的打印机设置,以便用户可以更改打印机的页面源和双面打印属性。

当我们开始将代码转换为 C# 时,我发现 MS Word API 中没有一个函数可以更改打印机的双面打印属性。Word 确实在 WordApplication 类的 PrintOut 方法中提供了一个参数,但 Microsoft 建议不要使用它,因为它依赖于操作系统和语言。

真正令人担忧的是 .NET 中的打印库。我没有找到任何可以在没有关联 PrintDocument 的情况下更改打印机设置的类。我真的觉得 .NET 应该提供一个更改打印机设置的类,或者至少提供一个帮助防止开发人员最终使用依赖于操作系统的 WIN API 的库(我最终设计了一个与操作系统无关的打印机类)。

另一个问题是,OpenPrinter 对网络打印机不起作用(尽管 Microsoft 建议设置打印机的方法,但我无法在客户端上这样做)。有趣的是,VB6 代码可以毫无问题地工作(访问被拒绝),并且所有 MS Office 工具都可以正常工作,那么为什么 C# 代码不行?

以下是使用 C# 修改全局打印机设置的代码。这只是一个示例代码。请原谅我,代码写得不够优雅,唯一目的是解释它的工作原理。该代码对网络打印机不起作用。请参阅以下链接以获取有关设置网络打印机的更多信息。

public class PrinterSettings 
{
#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 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 "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)]
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 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.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);*/
#endregion
#region "Data structure"
[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_DEFAULTS
{
public int pDatatype;
public int pDevMode;
public int DesiredAccess;
}
/*[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public struct PRINTER_DEFAULTS
{
public int pDataType;
public IntPtr pDevMode;
public ACCESS_MASK 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; 
}
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 "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" 
public bool ChangePrinterSetting(string PrinterName,PrinterData PS)

{

if (((int)PS.Duplex < 1) || ((int)PS.Duplex > 3) )
{
throw new ArgumentOutOfRangeException("nDuplexSetting",
                         "nDuplexSetting is incorrect.");
}
else
{
dm = this.GetPrinterSettings( PrinterName);
dm.dmDefaultSource =(short)PS.source; 
dm.dmOrientation = (short)PS.Orientation; 
dm.dmPaperSize =(short)PS.Size;
dm.dmDuplex = (short)PS.Duplex; 
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)
{
//Unable to set shared printer settings.
lastError = Marshal.GetLastWin32Error();
//string myErrMsg = GetErrorMessage(lastError);
throw new Win32Exception(Marshal.GetLastWin32Error()); 

}
if (hPrinter != IntPtr.Zero) 
ClosePrinter(hPrinter);
return Convert.ToBoolean(nRet);
}
}
private DEVMODE GetPrinterSettings(string PrinterName)
{
PrinterData PData = new PrinterData(); 
DEVMODE dm;
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);
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;
}
#endregion
}}
© . All rights reserved.