C#设置打印首选项
注意:如果有非DEVMODE标准的属性需要配置,请跳过这段直接看到踩坑
[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
const int CCHDEVICENAME = (32 * 2);
const int CCHFORMNAME = (32 * 2);
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
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 = CCHFORMNAME)]
public string dmFormName;
public short dmUnusedPadding;
public short dmBitsPerPel;
public int dmPelsWidth;
public int dmPelsHeight;
public int dmDisplayFlags;
public int dmDisplayFrequency;
public int dmICMMethod;
public int dmICMIntent;
public int dmMediaType;
public int dmDitherType;
public int dmICCManufacturer;
public int dmICCModel;
public int dmPanningWidth;
public int dmPanningHeight;
}
public class FunctionClass
{
[DllImport("winspool.Drv",
EntryPoint = "DocumentPropertiesA",
SetLastError = true,
ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter, [MarshalAs(UnmanagedType.LPStr)] string pDeviceNameg, IntPtr pDevModeOutput, ref IntPtr pDevModeInput, int fMode);
}
public class GCFunction
{
[DllImport("kernel32.dll")]
public static extern IntPtr GlobalAlloc(short uFlags, int dwBytes);
[DllImport("kernel32.dll")]
public static extern IntPtr GlobalLock(IntPtr hMem);
[DllImport("kernel32.dll")]
public static extern int GlobalFree(IntPtr hMem);
[DllImport("kernel32.dll", ExactSpelling = true)]
public static extern IntPtr GlobalUnlock(IntPtr handle);
[DllImport("kernel32.dll",
EntryPoint = "RtlMoveMemory")]
public static extern void Mem2DevCopy(out DEVMODE hpvDest,IntPtr hpvSource,int cbCopy);
}
// 全局变量
private DEVMODE dm;
private IntPtr pDevMode;
private IntPtr devModePtr;
/// <summary>
/// 读取初始配置
/// </summary>
private void GetDevMode()
{
IntPtr printerSlef = IntPtr.Zero;
int n = 0;
// 空默认不使用
IntPtr temp = new IntPtr();
try
{
if (!FunctionClass.OpenPrinter(printName, out printerSlef, 0))
{
throw new Exception("Cannot open printer");
}
// 正式获取结构体
pDevMode = pd.PrinterSettings.GetHdevmode(pd.PrinterSettings.DefaultPageSettings);
devModePtr = GCFunction.GlobalLock(pDevMode);
GetDevMode(printerSlef);
// 获取额外配置项的起始位
while (true)
{
if (dm.ExDevMode[n] == DevModeCode.EX_DEV_SIGN)
{
DevModeCode.ExDevTop = n - 1;
break;
}
if (n >= DevModeCode.EX_DEV_SIZE)
{
break;
}
n++;
}
}
finally
{
FunctionClass.ClosePrinter(printerSlef);
}
}
/// <summary>
/// 设置打印机
/// </summary>
public void SettingPrint(PrinterSet printerSet)
{
try
{
dm = Marshal.PtrToStructure<DEVMODE>(devModePtr);
// 修改DEVMODE
// 将修改之后dm同步内存
Marshal.StructureToPtr(dm, devModePtr, true);
pd.PrinterSettings.SetHdevmode(devModePtr);
}
finally
{
GCFunction.GlobalUnlock(devModePtr);
GCFunction.GlobalFree(pDevMode);
}
}
/// <summary>
/// 手动获取DevMod内容
/// </summary>
/// <param name="devModePtr"> 已被分配内存的指针 </param>
/// <param name="dm"> 回传结构体 </param>
/// <exception cref="Exception"></exception>
public void GetDevMode(IntPtr printerSlef)
{
IntPtr tempNull = IntPtr.Zero;
int resultCode;
// 再次访问获取实际数据
resultCode = FunctionClass.DocumentProperties(0, printerSlef, printName, devModePtr, ref tempNull, DevModeCode.DM_OUT_BUFFER);
if (resultCode < 0)
{
GCFunction.GlobalUnlock(devModePtr);
GCFunction.GlobalFree(pDevMode);
devModePtr = pDevMode = IntPtr.Zero;
throw new Exception("Cannot get DevMode"); ;
}
dm = Marshal.PtrToStructure<DEVMODE>(devModePtr);
if (string.IsNullOrEmpty(dm.dmDeviceName))
{
GCFunction.GlobalUnlock(devModePtr);
GCFunction.GlobalFree(pDevMode);
devModePtr = pDevMode = IntPtr.Zero;
throw new Exception("Cannot make intptr to DevMode"); ;
}
}
如果出错了,记得外部方法出错了记得使用 Marshal.GetLastWin32Error()查看错误
配置额外的配置项
当我在配置打印机提供的额外配置项时老是不生效,导致抓耳挠腮,后面调试后发现SetHdevmode()使用的时Gdi.DEVMODE的标准类,导致额外添加的属性没法生效……
所以我用VB写了个DLL提供C#调用解决,因为VB的生效且方便C#调用
Public Function SettingPrinter(hPrinter As IntPtr)
Dim ResultCode As Integer
Dim DevModeSize As Integer
Dim n, ExDevTop As Integer
Dim dmw As DEVMODEW = Nothing
Dim hDevMode As Long
Dim lpDevModeDmW As IntPtr
DevModeSize = DocumentProperties(0, hPrinter, printerName, IntPtr.Zero, IntPtr.Zero, 0)
If DevModeSize = 0 Then
Exit Function
End If
hDevMode = GlobalAlloc(GHND, DevModeSize)
lpDevModeDmW = GlobalLock(hDevMode)
ResultCode = DocumentProperties(0, hPrinter, printerName, lpDevModeDmW, 0, DM_OUT_BUFFER)
If ResultCode < 0 Then
GlobalFree(lpDevModeDmW)
Exit Function
End If
Mem2DevCopy(dmw, lpDevModeDmW, DevModeSize)
'配置DEVMODE
Call Dev2MemCopy(lpDevModeDmW, dmw, DevModeSize)
printerDocuent.PrinterSettings.SetHdevmode(lpDevModeDmW)
ResultCode = GlobalFree(lpDevModeDmW)
End Function
Declare Function DocumentProperties Lib "winspool.drv" Alias "DocumentPropertiesW" _
(ByVal hwnd As Integer,
ByVal hPrinter As IntPtr,
ByVal pDeviceName As String,
ByVal pDevModeOutput As IntPtr,
ByVal pDevModeInput As IntPtr,
ByVal fMode As Integer) As Integer
Public Declare Function GlobalAlloc Lib "kernel32" _
(ByVal uFlags As Short,
ByVal dwBytes As Long) As Long
Public Declare Function GlobalFree Lib "kernel32" _
(ByVal hMem As Long) As Long
Public Declare Function GlobalLock Lib "kernel32" _
(ByVal hMem As Long) As Long
Private Declare Sub Mem2DevCopy Lib "kernel32" Alias "RtlMoveMemory" _
(ByRef hpvDest As DEVMODEW,
ByVal hpvSource As IntPtr,
ByVal cbCopy As Integer)
Private Declare Sub Dev2MemCopy Lib "kernel32" Alias "RtlMoveMemory" _
(ByVal hpvDest As IntPtr,
ByRef hpvSource As DEVMODEW,
ByVal cbCopy As Integer)
Public Const EX_DEV_SIZE As Short = 1024
Public Const GMEM_FIXED As Integer = &H0
Public Const GMEM_MOVEABLE As Integer = &H2
Public Const GMEM_ZEROINIT As Integer = &H40
Public Const GHND As Integer = (GMEM_MOVEABLE Or GMEM_ZEROINIT)
Public Const DM_UPDATE As Integer = 1
Public Const DM_COPY As Integer = 2
Public Const DM_PROMPT As Integer = 4
Public Const DM_MODIFY As Integer = 8
Public Const DM_IN_BUFFER As Integer = DM_MODIFY
Public Const DM_IN_PROMPT As Integer = DM_PROMPT
Public Const DM_OUT_BUFFER As Integer = DM_COPY
Public Const DM_OUT_DEFAULT As Integer = DM_UPDATE
<StructLayout(LayoutKind.Sequential)>
Public Structure DEVMODEW
Const CCHDEVICENAME As Integer = (32 * 2)
Const CCHFORMNAME As Integer = (32 * 2)
<VBFixedArray(CCHDEVICENAME - 1),
MarshalAs(UnmanagedType.ByValArray,
SizeConst:=CCHDEVICENAME)> Public dmDeviceName As Byte()
Dim dmSpecVersion As Short
Dim dmDriverVersion As Short
Dim dmSize As Short
Dim dmDriverExtra As Short
Dim dmFields As Integer
Dim dmOrientation As Short
Dim dmPaperSize As Short
Dim dmPaperLength As Short
Dim dmPaperWidth As Short
Dim dmScale As Short
Dim dmCopies As Short
Dim dmDefaultSource As Short
Dim dmPrintQuality As Short
Dim dmColor As Short
Dim dmDuplex As Short
Dim dmYResolution As Short
Dim dmTTOption As Short
Dim dmCollate As Short
<VBFixedArray(CCHFORMNAME - 1),
MarshalAs(UnmanagedType.ByValArray,
SizeConst:=CCHFORMNAME)> Public dmFormName As Byte()
Dim dmUnusedPadding As Short
Dim dmBitsPerPel As Integer
Dim dmPelsWidth As Integer
Dim dmPelsHeight As Integer
Dim dmDisplayFlags As Integer
Dim dmDisplayFrequency As Integer
Dim dmICMMethod As Integer
Dim dmICMIntent As Integer
Dim dmMediaType As Integer
Dim dmDitherType As Integer
Dim dmICCManufacturer As Integer
Dim dmICCModel As Integer
Dim dmPanningWidth As Integer
Dim dmPanningHeight As Integer
'额外属性
End Structure