在 C# 中使用 PrintSpoolerAPI 函数 SetForm()
Use PrintSpoolerAPI function SetForm() in C#
我正在开发 Windows 表单应用程序,我想在其中打印自定义文档。此自定义文档是自定义大小,我必须使用 C# 代码设置默认打印页面大小。
我进行了一些 google 搜索并找到了 PrintSpoolerAPI
。我找到的代码将使用 AddForm()
方法将自定义 form/page 添加到可用页面列表以进行打印。 我也想将这个新添加的页面设置为默认打印页面。
我试着在代码中写下这一行
bool x = SetForm(hPrinter, paperName, 1, ref formInfo);
它 returns 是一个 true
值,但它没有设置默认打印页面。
dmPaperSize
在其中有什么作用吗?
完整代码如下:
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Security;
using System.ComponentModel;
using System.Drawing.Printing;
namespace WindowsFormsApplication1
{
public class CustomPrintForm
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct structPrinterDefaults
{
[MarshalAs(UnmanagedType.LPTStr)]
public String pDatatype;
public IntPtr pDevMode;
[MarshalAs(UnmanagedType.I4)]
public int DesiredAccess;
};
[DllImport("winspool.Drv", EntryPoint = "OpenPrinter", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall),
SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPTStr)]
string printerName,
out IntPtr phPrinter,
ref structPrinterDefaults pd);
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = false,
CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool ClosePrinter(IntPtr phPrinter);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct structSize
{
public Int32 width;
public Int32 height;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct structRect
{
public Int32 left;
public Int32 top;
public Int32 right;
public Int32 bottom;
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
internal struct FormInfo1
{
[FieldOffset(0), MarshalAs(UnmanagedType.I4)]
public uint Flags;
[FieldOffset(4), MarshalAs(UnmanagedType.LPWStr)]
public String pName;
[FieldOffset(8)]
public structSize Size;
[FieldOffset(16)]
public structRect ImageableArea;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi/* changed from CharSet=CharSet.Auto */)]
internal struct structDevMode
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public String
dmDeviceName;
[MarshalAs(UnmanagedType.U2)]
public short dmSpecVersion;
[MarshalAs(UnmanagedType.U2)]
public short dmDriverVersion;
[MarshalAs(UnmanagedType.U2)]
public short dmSize;
[MarshalAs(UnmanagedType.U2)]
public short dmDriverExtra;
[MarshalAs(UnmanagedType.U4)]
public int dmFields;
[MarshalAs(UnmanagedType.I2)]
public short dmOrientation;
[MarshalAs(UnmanagedType.I2)]
public short dmPaperSize;
[MarshalAs(UnmanagedType.I2)]
public short dmPaperLength;
[MarshalAs(UnmanagedType.I2)]
public short dmPaperWidth;
[MarshalAs(UnmanagedType.I2)]
public short dmScale;
[MarshalAs(UnmanagedType.I2)]
public short dmCopies;
[MarshalAs(UnmanagedType.I2)]
public short dmDefaultSource;
[MarshalAs(UnmanagedType.I2)]
public short dmPrintQuality;
[MarshalAs(UnmanagedType.I2)]
public short dmColor;
[MarshalAs(UnmanagedType.I2)]
public short dmDuplex;
[MarshalAs(UnmanagedType.I2)]
public short dmYResolution;
[MarshalAs(UnmanagedType.I2)]
public short dmTTOption;
[MarshalAs(UnmanagedType.I2)]
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public String dmFormName;
[MarshalAs(UnmanagedType.U2)]
public short dmLogPixels;
[MarshalAs(UnmanagedType.U4)]
public int dmBitsPerPel;
[MarshalAs(UnmanagedType.U4)]
public int dmPelsWidth;
[MarshalAs(UnmanagedType.U4)]
public int dmPelsHeight;
[MarshalAs(UnmanagedType.U4)]
public int dmNup;
[MarshalAs(UnmanagedType.U4)]
public int dmDisplayFrequency;
[MarshalAs(UnmanagedType.U4)]
public int dmICMMethod;
[MarshalAs(UnmanagedType.U4)]
public int dmICMIntent;
[MarshalAs(UnmanagedType.U4)]
public int dmMediaType;
[MarshalAs(UnmanagedType.U4)]
public int dmDitherType;
[MarshalAs(UnmanagedType.U4)]
public int dmReserved1;
[MarshalAs(UnmanagedType.U4)]
public int dmReserved2;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct PRINTER_INFO_9
{
public IntPtr pDevMode;
}
[DllImport("winspool.Drv", EntryPoint = "AddFormW", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool AddForm(
IntPtr phPrinter,
[MarshalAs(UnmanagedType.I4)] int level,
ref FormInfo1 form);
[DllImport("winspool.Drv", EntryPoint = "SetForm", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = false,
CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool SetForm(IntPtr phPrinter, string paperName,
[MarshalAs(UnmanagedType.I4)] int level, ref FormInfo1 form);
[DllImport("winspool.Drv", EntryPoint = "DeleteForm", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall),
SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool DeleteForm(
IntPtr phPrinter,
[MarshalAs(UnmanagedType.LPTStr)] string pName);
[DllImport("kernel32.dll", EntryPoint = "GetLastError", SetLastError = false,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall),
SuppressUnmanagedCodeSecurityAttribute()]
internal static extern Int32 GetLastError();
[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 structDevMode 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 structDevMode
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 = "SetPrinterA", SetLastError = true,
CharSet = CharSet.Auto, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool SetPrinter(
IntPtr hPrinter,
[MarshalAs(UnmanagedType.I4)] int level,
IntPtr pPrinter,
[MarshalAs(UnmanagedType.I4)] int command);
/*
LONG DocumentProperties(
HWND hWnd, // handle to parent window
HANDLE hPrinter, // handle to printer object
LPTSTR pDeviceName, // device name
PDEVMODE pDevModeOutput, // modified device mode
PDEVMODE pDevModeInput, // original device mode
DWORD fMode // mode options
);
*/
[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 pDeviceName /* changed from String to string */,
IntPtr pDevModeOutput,
IntPtr pDevModeInput,
int fMode
);
[DllImport("winspool.Drv", EntryPoint = "GetPrinterA", SetLastError = true,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool GetPrinter(
IntPtr hPrinter,
int dwLevel /* changed type from Int32 */,
IntPtr pPrinter,
int dwBuf /* chagned from Int32*/,
out int dwNeeded /* changed from Int32*/
);
// SendMessageTimeout tools
[Flags]
public enum SendMessageTimeoutFlags : uint
{
SMTO_NORMAL = 0x0000,
SMTO_BLOCK = 0x0001,
SMTO_ABORTIFHUNG = 0x0002,
SMTO_NOTIMEOUTIFNOTHUNG = 0x0008
}
const int WM_SETTINGCHANGE = 0x001A;
const int HWND_BROADCAST = 0xffff;
[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
);
public static void AddMjm80MmPaperSizeToDefaultPrinter()
{
AddCustomPaperSizeToDefaultPrinter("MJM 80mm * Receipt Length", 80.1f, 4003.9f);
}
public static void AddMjm104MmPaperSizeToDefaultPrinter()
{
AddCustomPaperSizeToDefaultPrinter("MJM 104mm * Receipt Length", 104.1f, 4003.9f);
}
/// <summary>
/// Adds the printer form to the default printer
/// </summary>
/// <param name="paperName">Name of the printer form</param>
/// <param name="widthMm">Width given in millimeters</param>
/// <param name="heightMm">Height given in millimeters</param>
public static void AddCustomPaperSizeToDefaultPrinter(string paperName, float widthMm, float heightMm)
{
PrintDocument pd = new PrintDocument();
string sPrinterName = pd.PrinterSettings.PrinterName;
AddCustomPaperSize(sPrinterName, paperName, widthMm, heightMm);
}
/// <summary>
/// Add the printer form to a printer
/// </summary>
/// <param name="printerName">The printer name</param>
/// <param name="paperName">Name of the printer form</param>
/// <param name="widthMm">Width given in millimeters</param>
/// <param name="heightMm">Height given in millimeters</param>
public static void AddCustomPaperSize(string printerName, string paperName, float
widthMm, float heightMm)
{
if (PlatformID.Win32NT == Environment.OSVersion.Platform)
{
// The code to add a custom paper size is different for Windows NT then it is
// for previous versions of windows
const int PRINTER_ACCESS_USE = 0x00000008;
const int PRINTER_ACCESS_ADMINISTER = 0x00000004;
const int FORM_PRINTER = 0x00000002;
structPrinterDefaults defaults = new structPrinterDefaults();
defaults.pDatatype = null;
defaults.pDevMode = IntPtr.Zero;
defaults.DesiredAccess = PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE;
IntPtr hPrinter = IntPtr.Zero;
// Open the printer.
if (OpenPrinter(printerName, out hPrinter, ref defaults))
{
try
{
// delete the form incase it already exists
DeleteForm(hPrinter, paperName);
// create and initialize the FORM_INFO_1 structure
FormInfo1 formInfo = new FormInfo1();
formInfo.Flags = 0;
formInfo.pName = paperName;
// all sizes in 1000ths of millimeters
formInfo.Size.width = (int)(widthMm * 1000.0);
formInfo.Size.height = (int)(heightMm * 1000.0);
formInfo.ImageableArea.left = 0;
formInfo.ImageableArea.right = formInfo.Size.width;
formInfo.ImageableArea.top = 0;
formInfo.ImageableArea.bottom = formInfo.Size.height;
if (!AddForm(hPrinter, 1, ref formInfo))
{
StringBuilder strBuilder = new StringBuilder();
strBuilder.AppendFormat("Failed to add the custom paper size {0} to the printer {1}, System error number: {2}",
paperName, printerName, GetLastError());
throw new ApplicationException(strBuilder.ToString());
}
else
{
bool x = SetForm(hPrinter, paperName, 1, ref formInfo);
}
// INIT
const int DM_OUT_BUFFER = 2;
const int DM_IN_BUFFER = 8;
structDevMode devMode = new structDevMode();
IntPtr hPrinterInfo, hDummy;
PRINTER_INFO_9 printerInfo;
printerInfo.pDevMode = IntPtr.Zero;
int iPrinterInfoSize, iDummyInt;
// GET THE SIZE OF THE DEV_MODE BUFFER
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.");
// ALLOCATE THE BUFFER
IntPtr hDevMode = Marshal.AllocCoTaskMem(iDevModeSize + 100);
// GET A POINTER TO THE DEV_MODE BUFFER
int iRet = DocumentProperties(IntPtr.Zero, hPrinter, printerName, hDevMode, IntPtr.Zero, DM_OUT_BUFFER);
if (iRet < 0)
throw new ApplicationException("Cannot get the DEVMODE structure.");
// FILL THE DEV_MODE STRUCTURE
devMode = (structDevMode)Marshal.PtrToStructure(hDevMode, devMode.GetType());
// SET THE FORM NAME FIELDS TO INDICATE THAT THIS FIELD WILL BE MODIFIED
devMode.dmFields = 0x10000; // DM_FORMNAME
// SET THE FORM NAME
devMode.dmFormName = paperName;
// PUT THE DEV_MODE STRUCTURE BACK INTO THE POINTER
Marshal.StructureToPtr(devMode, hDevMode, true);
// MERGE THE NEW CHAGES WITH THE OLD
iRet = DocumentProperties(IntPtr.Zero, hPrinter, printerName,
printerInfo.pDevMode, printerInfo.pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER);
if (iRet < 0)
throw new ApplicationException("Unable to set the orientation setting for this printer.");
// GET THE PRINTER INFO SIZE
GetPrinter(hPrinter, 9, IntPtr.Zero, 0, out iPrinterInfoSize);
if (iPrinterInfoSize == 0)
throw new ApplicationException("GetPrinter failed. Couldn't get the # bytes needed for shared PRINTER_INFO_9 structure");
// ALLOCATE THE BUFFER
hPrinterInfo = Marshal.AllocCoTaskMem(iPrinterInfoSize + 100);
// GET A POINTER TO THE PRINTER INFO BUFFER
bool bSuccess = GetPrinter(hPrinter, 9, hPrinterInfo, iPrinterInfoSize, out iDummyInt);
if (!bSuccess)
throw new ApplicationException("GetPrinter failed. Couldn't get the shared PRINTER_INFO_9 structure");
// FILL THE PRINTER INFO STRUCTURE
printerInfo = (PRINTER_INFO_9)Marshal.PtrToStructure(hPrinterInfo, printerInfo.GetType());
printerInfo.pDevMode = hDevMode;
// GET A POINTER TO THE PRINTER INFO STRUCTURE
Marshal.StructureToPtr(printerInfo, hPrinterInfo, true);
// SET THE PRINTER SETTINGS
bSuccess = SetPrinter(hPrinter, 9, hPrinterInfo, 0);
if (!bSuccess)
throw new Win32Exception(Marshal.GetLastWin32Error(), "SetPrinter() failed. Couldn't set the printer settings");
// Tell all open programs that this change occurred.
SendMessageTimeout(new IntPtr(HWND_BROADCAST), WM_SETTINGCHANGE, IntPtr.Zero, IntPtr.Zero, CustomPrintForm.SendMessageTimeoutFlags.SMTO_NORMAL, 1000, out hDummy);
}
finally
{
ClosePrinter(hPrinter);
}
}
else
{
StringBuilder strBuilder = new StringBuilder();
strBuilder.AppendFormat("Failed to open the {0} printer, System error number: {1}",
printerName, GetLastError());
throw new ApplicationException(strBuilder.ToString());
}
}
else
{
structDevMode pDevMode = new structDevMode();
IntPtr hDC = CreateDC(null, printerName, null, ref pDevMode);
if (hDC != IntPtr.Zero)
{
const long DM_PAPERSIZE = 0x00000002L;
const long DM_PAPERLENGTH = 0x00000004L;
const long DM_PAPERWIDTH = 0x00000008L;
pDevMode.dmFields = (int)(DM_PAPERSIZE | DM_PAPERWIDTH | DM_PAPERLENGTH);
pDevMode.dmPaperSize = 256;
pDevMode.dmPaperWidth = (short)(widthMm * 1000.0);
pDevMode.dmPaperLength = (short)(heightMm * 1000.0);
ResetDC(hDC, ref pDevMode);
DeleteDC(hDC);
}
}
}
}
}
需要帮助解决这个问题。
您的代码几乎完美无缺(需要在 64 位模式下工作)并且完成了预期的工作:
然而,好消息到此为止。您正在使用的 api 直接与打印机驱动程序对话,它负责确保您的 DEVMODE 更改生效。这适用于 XPS 打印机驱动程序,但不适用于许多其他类型的驱动程序。好像惠普的驱动我也试过了
您所做的一切都会在注册表中立即显示 side-effect。你可以用Regedit.exe看到它。这是 double-check 您的代码的好方法。要看到它,您需要停止尝试,因为打印机驱动程序不会 co-operate。你想看的按键:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Forms。此键列出您添加的表单。你应该不会有那个问题。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Forms\MJM 80mm * 收据长度,"FormKeyword" 值。记下来,就是打印机选择你的表格的"keyword"
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Printers\printername、"Default DevMode"值。这是在您调用 SetPrinter() 时写入的。您可以查看该值的十六进制转储。您在上一步中记下的 FormKeyword 在偏移量 0x348
处可见
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Printers\printername\DsDriver,printMediaSupported 值。对此不完全确定,但应该显示纸张尺寸列表,并且您的自定义表单应该在那里可见。
不好意思,打印机很烂。
x64 使用
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
internal struct FormInfo1
{
[FieldOffset(0), MarshalAs(UnmanagedType.I4)]
public uint Flags;
[FieldOffset(8), MarshalAs(UnmanagedType.LPWStr)]
public String pName;
[FieldOffset(16)]
public structSize Size;
[FieldOffset(24)]
public structRect ImageableArea;
};
感谢Nilesh 的代码和Hans 的注册信息,我的要求是通过c# 程序为特定打印机设置默认页面大小,然后打开网络浏览器打印特定网页。
现在我尝试添加我的自定义页面表单,并将 dmFormName 设置为默认值。然后我重新获取 devmode struct , dmFormName 是我更改的,但是当我打开记事本或其他应用程序并尝试打印一些东西时,我看到默认的页面大小不是我设置的。
我也尝试删除所有未使用的pagesizes,这样默认只有一个,但只能删除自己添加的pagesizes。
PS:我做了一些代码重构如下:
internal class PrinterPagaSize
{
public void DeleteAllPrintForm(string printerName)
{
structPrinterDefaults defaults = InitPrinterDefaults();
IntPtr hPrinter = IntPtr.Zero;
if (OpenPrinter(printerName, out hPrinter, ref defaults))
{
try
{
var printerSettings = PrinterSelector.DefaultPrinterSettings;
foreach (PaperSize ps in printerSettings.PaperSizes)
{
bool ret = DeleteForm(hPrinter, ps.PaperName);
Debug.WriteLine("delete ret:" + ret.ToString());
}
}
finally
{
ClosePrinter(hPrinter);
}
}
}
public PaperSize GetPrintForm(string printerName, string paperName)
{
PaperSize paper = null;
//var printer = new System.Drawing.Printing.PrinterSettings {PrinterName = printerName};
var printer = PrinterSelector.DefaultPrinterSettings;
foreach (PaperSize ps in printer.PaperSizes)
{
if (ps.PaperName.ToLower() == paperName.ToLower())
{
paper = ps;
break;
}
}
return paper;
}
/// <summary>
/// Add the printer form to a printer
/// </summary>
/// <param name="printerName">The printer name</param>
/// <param name="paperName">Name of the printer form</param>
/// <param name="widthMm">Width given in millimeters</param>
/// <param name="heightMm">Height given in millimeters</param>
public void AddCustomPaperSize(string printerName, string paperName, float
width, float height)
{
if (PlatformID.Win32NT == Environment.OSVersion.Platform)
{
// The code to add a custom paper size is different for Windows NT then it is
// for previous versions of windows
structPrinterDefaults defaults = InitPrinterDefaults();
IntPtr hPrinter = IntPtr.Zero;
// Open the printer.
if (OpenPrinter(printerName, out hPrinter, ref defaults))
{
try
{
// delete the form incase it already exists
DeleteForm(hPrinter, paperName);
// create and initialize the FORM_INFO_1 structure
FormInfo1 formInfo = new FormInfo1();
formInfo.Flags = 0;
formInfo.pName = paperName;
// all sizes in 1000ths of millimeters
formInfo.Size.width = (int)(width * 100.0);
formInfo.Size.height = (int)(height * 100.0);
formInfo.ImageableArea.left = 0;
formInfo.ImageableArea.right = formInfo.Size.width;
formInfo.ImageableArea.top = 0;
formInfo.ImageableArea.bottom = formInfo.Size.height;
if (!AddForm(hPrinter, 1, ref formInfo))
{
StringBuilder strBuilder = new StringBuilder();
strBuilder.AppendFormat(
"Failed to add the custom paper size {0} to the printer {1}, System error number: {2}",
paperName, printerName, GetLastError());
throw new ApplicationException(strBuilder.ToString());
}
else
{
SetForm(hPrinter, paperName, 1, ref formInfo);
}
SetPrinterDevMode(hPrinter, printerName, paperName);
}
finally
{
ClosePrinter(hPrinter);
}
}
else
{
StringBuilder strBuilder = new StringBuilder();
strBuilder.AppendFormat("Failed to open the {0} printer, System error number: {1}",
printerName, GetLastError());
throw new ApplicationException(strBuilder.ToString());
}
}
else
{
structDevMode pDevMode = new structDevMode();
IntPtr hDC = CreateDC(null, printerName, null, ref pDevMode);
if (hDC != IntPtr.Zero)
{
const long DM_PAPERSIZE = 0x00000002L;
const long DM_PAPERLENGTH = 0x00000004L;
const long DM_PAPERWIDTH = 0x00000008L;
pDevMode.dmFields = (int)(DM_PAPERSIZE | DM_PAPERWIDTH | DM_PAPERLENGTH);
pDevMode.dmPaperSize = 256;
pDevMode.dmPaperWidth = (short)(width * 1000.0);
pDevMode.dmPaperLength = (short)(height * 1000.0);
ResetDC(hDC, ref pDevMode);
DeleteDC(hDC);
}
}
}
const int DM_OUT_BUFFER = 2;
const int DM_IN_BUFFER = 8;
private void SetPrinterDevMode(IntPtr hPrinter, string printerName, string paperName)
{
// INIT
structDevMode devMode = new structDevMode();
PRINTER_INFO_9 printerInfo = new PRINTER_INFO_9();
printerInfo.pDevMode = IntPtr.Zero;
IntPtr hDevMode = GetDevMode(hPrinter, printerName, ref devMode);
// SET THE FORM NAME FIELDS TO INDICATE THAT THIS FIELD WILL BE MODIFIED
devMode.dmFields = 0x10000; // DM_FORMNAME
// SET THE FORM NAME
devMode.dmFormName = paperName;
ChangeDevMode(hPrinter, printerName, paperName, devMode, hDevMode, ref printerInfo);
IntPtr hPrinterInfo = GetPrinterInfo(hPrinter);
// FILL THE PRINTER INFO STRUCTURE
printerInfo = (PRINTER_INFO_9)Marshal.PtrToStructure(hPrinterInfo, printerInfo.GetType());
printerInfo.pDevMode = hDevMode;
// GET A POINTER TO THE PRINTER INFO STRUCTURE
Marshal.StructureToPtr(printerInfo, hPrinterInfo, true);
// SET THE PRINTER SETTINGS
bool bSuccess = SetPrinter(hPrinter, 9, hPrinterInfo, 0);
if (!bSuccess)
throw new Exception("Set printer failed!");
}
private static IntPtr GetPrinterInfo(IntPtr hPrinter)
{
IntPtr hPrinterInfo;
bool bSuccess = false;
int iPrinterInfoSize, iDummyInt;
// GET THE PRINTER INFO SIZE
GetPrinter(hPrinter, 9, IntPtr.Zero, 0, out iPrinterInfoSize);
if (iPrinterInfoSize == 0)
throw new ApplicationException(
"GetPrinter failed. Couldn't get the # bytes needed for shared PRINTER_INFO_9 structure");
// ALLOCATE THE BUFFER
hPrinterInfo = Marshal.AllocCoTaskMem(iPrinterInfoSize + 100);
// GET A POINTER TO THE PRINTER INFO BUFFER
bSuccess = GetPrinter(hPrinter, 9, hPrinterInfo, iPrinterInfoSize, out iDummyInt);
if (!bSuccess)
throw new ApplicationException(
"GetPrinter failed. Couldn't get the shared PRINTER_INFO_9 structure");
return hPrinterInfo;
}
private static void ChangeDevMode(IntPtr hPrinter, string printerName, string paperName, structDevMode devMode, IntPtr hDevMode, ref PRINTER_INFO_9 printerInfo)
{
// PUT THE DEV_MODE STRUCTURE BACK INTO THE POINTER
Marshal.StructureToPtr(devMode, hDevMode, true);
// MERGE THE NEW CHAGES WITH THE OLD
int iRet = DocumentProperties(IntPtr.Zero, hPrinter, printerName,
printerInfo.pDevMode, printerInfo.pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER);
if (iRet < 0)
throw new ApplicationException("Unable to set the orientation setting for this printer.");
}
private static IntPtr GetDevMode(IntPtr hPrinter, string printerName, ref structDevMode devMode)
{
// GET THE SIZE OF THE DEV_MODE BUFFER
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.");
// ALLOCATE THE BUFFER
IntPtr hDevMode = Marshal.AllocCoTaskMem(iDevModeSize + 100);
// GET A POINTER TO THE DEV_MODE BUFFER
int iRet = DocumentProperties(IntPtr.Zero, hPrinter, printerName, hDevMode, IntPtr.Zero,
DM_OUT_BUFFER);
if (iRet < 0)
throw new ApplicationException("Cannot get the DEVMODE structure.");
// FILL THE DEV_MODE STRUCTURE
devMode = (structDevMode)Marshal.PtrToStructure(hDevMode, devMode.GetType());
return hDevMode;
}
private static structPrinterDefaults InitPrinterDefaults()
{
const int PRINTER_ACCESS_USE = 0x00000008;
const int PRINTER_ACCESS_ADMINISTER = 0x00000004;
structPrinterDefaults defaults = new structPrinterDefaults();
defaults.pDatatype = null;
defaults.pDevMode = IntPtr.Zero;
defaults.DesiredAccess = PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE;
return defaults;
}
#region Win API
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct structPrinterDefaults
{
[MarshalAs(UnmanagedType.LPTStr)]
public String pDatatype;
public IntPtr pDevMode;
[MarshalAs(UnmanagedType.I4)]
public int DesiredAccess;
};
[DllImport("winspool.Drv", EntryPoint = "OpenPrinter", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall),
SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPTStr)] string printerName,
out IntPtr phPrinter,
ref structPrinterDefaults pd);
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = false,
CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool ClosePrinter(IntPtr phPrinter);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct structSize
{
public Int32 width;
public Int32 height;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct structRect
{
public Int32 left;
public Int32 top;
public Int32 right;
public Int32 bottom;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct FormInfo1
{
[MarshalAs(UnmanagedType.I4)]
public int Flags;
[MarshalAs(UnmanagedType.LPTStr)]
public String pName;
public structSize Size;
public structRect ImageableArea;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi /* changed from CharSet=CharSet.Auto */)]
internal struct structDevMode
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public String
dmDeviceName;
[MarshalAs(UnmanagedType.U2)]
public short dmSpecVersion;
[MarshalAs(UnmanagedType.U2)]
public short dmDriverVersion;
[MarshalAs(UnmanagedType.U2)]
public short dmSize;
[MarshalAs(UnmanagedType.U2)]
public short dmDriverExtra;
[MarshalAs(UnmanagedType.U4)]
public int dmFields;
[MarshalAs(UnmanagedType.I2)]
public short dmOrientation;
[MarshalAs(UnmanagedType.I2)]
public short dmPaperSize;
[MarshalAs(UnmanagedType.I2)]
public short dmPaperLength;
[MarshalAs(UnmanagedType.I2)]
public short dmPaperWidth;
[MarshalAs(UnmanagedType.I2)]
public short dmScale;
[MarshalAs(UnmanagedType.I2)]
public short dmCopies;
[MarshalAs(UnmanagedType.I2)]
public short dmDefaultSource;
[MarshalAs(UnmanagedType.I2)]
public short dmPrintQuality;
[MarshalAs(UnmanagedType.I2)]
public short dmColor;
[MarshalAs(UnmanagedType.I2)]
public short dmDuplex;
[MarshalAs(UnmanagedType.I2)]
public short dmYResolution;
[MarshalAs(UnmanagedType.I2)]
public short dmTTOption;
[MarshalAs(UnmanagedType.I2)]
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public String dmFormName;
[MarshalAs(UnmanagedType.U2)]
public short dmLogPixels;
[MarshalAs(UnmanagedType.U4)]
public int dmBitsPerPel;
[MarshalAs(UnmanagedType.U4)]
public int dmPelsWidth;
[MarshalAs(UnmanagedType.U4)]
public int dmPelsHeight;
[MarshalAs(UnmanagedType.U4)]
public int dmNup;
[MarshalAs(UnmanagedType.U4)]
public int dmDisplayFrequency;
[MarshalAs(UnmanagedType.U4)]
public int dmICMMethod;
[MarshalAs(UnmanagedType.U4)]
public int dmICMIntent;
[MarshalAs(UnmanagedType.U4)]
public int dmMediaType;
[MarshalAs(UnmanagedType.U4)]
public int dmDitherType;
[MarshalAs(UnmanagedType.U4)]
public int dmReserved1;
[MarshalAs(UnmanagedType.U4)]
public int dmReserved2;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct PRINTER_INFO_9
{
public IntPtr pDevMode;
}
[DllImport("winspool.Drv", EntryPoint = "AddFormW", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool AddForm(
IntPtr phPrinter,
[MarshalAs(UnmanagedType.I4)] int level,
ref FormInfo1 form);
[DllImport("winspool.Drv", EntryPoint = "SetForm", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = false,
CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool SetForm(IntPtr phPrinter, string paperName,
[MarshalAs(UnmanagedType.I4)] int level, ref FormInfo1 form);
[DllImport("winspool.Drv", EntryPoint = "DeleteForm", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall),
SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool DeleteForm(
IntPtr phPrinter,
[MarshalAs(UnmanagedType.LPTStr)] string pName);
[DllImport("kernel32.dll", EntryPoint = "GetLastError", SetLastError = false,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall),
SuppressUnmanagedCodeSecurityAttribute()]
internal static extern Int32 GetLastError();
[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 structDevMode 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 structDevMode
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 = "SetPrinterA", SetLastError = true,
CharSet = CharSet.Auto, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool SetPrinter(
IntPtr hPrinter,
[MarshalAs(UnmanagedType.I4)] int level,
IntPtr pPrinter,
[MarshalAs(UnmanagedType.I4)] int command);
/*
LONG DocumentProperties(
HWND hWnd, // handle to parent window
HANDLE hPrinter, // handle to printer object
LPTSTR pDeviceName, // device name
PDEVMODE pDevModeOutput, // modified device mode
PDEVMODE pDevModeInput, // original device mode
DWORD fMode // mode options
);
*/
[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 pDeviceName /* changed from String to string */,
IntPtr pDevModeOutput,
IntPtr pDevModeInput,
int fMode
);
[DllImport("winspool.Drv", EntryPoint = "GetPrinterA", SetLastError = true,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool GetPrinter(
IntPtr hPrinter,
int dwLevel /* changed type from Int32 */,
IntPtr pPrinter,
int dwBuf /* chagned from Int32*/,
out int dwNeeded /* changed from Int32*/
);
// SendMessageTimeout tools
[Flags]
public enum SendMessageTimeoutFlags : uint
{
SMTO_NORMAL = 0x0000,
SMTO_BLOCK = 0x0001,
SMTO_ABORTIFHUNG = 0x0002,
SMTO_NOTIMEOUTIFNOTHUNG = 0x0008
}
private const int WM_SETTINGCHANGE = 0x001A;
private const int HWND_BROADCAST = 0xffff;
[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
}
我只是使用类似的代码将特殊纸张尺寸添加到我们的自定义 windows 打印机驱动程序中。似乎有时它不起作用,但原因是打印机的驱动程序 GPD 文件。如果此文件中不存在 CUSTOMIZE 特殊部分,打印机将永远不会接受任何自定义纸张尺寸。您可以使用标准 windows 程序轻松检查将自定义纸张添加到任何打印机。
*Option: CUSTOMSIZE
{
*rcNameID: =USER_DEFINED_SIZE_DISPLAY
*MinSize: PAIR(100, 100)
*MaxSize: PAIR(4026, 11340)
*TopMargin: 0
*BottomMargin: 0
*MaxPrintableWidth: 4026
*MinLeftMargin: 0
*CenterPrintable?: FALSE
*Command: CmdSelect
{
*Order: DOC_SETUP.10
*Cmd: ""
}
}
我正在开发 Windows 表单应用程序,我想在其中打印自定义文档。此自定义文档是自定义大小,我必须使用 C# 代码设置默认打印页面大小。
我进行了一些 google 搜索并找到了 PrintSpoolerAPI
。我找到的代码将使用 AddForm()
方法将自定义 form/page 添加到可用页面列表以进行打印。 我也想将这个新添加的页面设置为默认打印页面。
我试着在代码中写下这一行
bool x = SetForm(hPrinter, paperName, 1, ref formInfo);
它 returns 是一个 true
值,但它没有设置默认打印页面。
dmPaperSize
在其中有什么作用吗?
完整代码如下:
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Security;
using System.ComponentModel;
using System.Drawing.Printing;
namespace WindowsFormsApplication1
{
public class CustomPrintForm
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct structPrinterDefaults
{
[MarshalAs(UnmanagedType.LPTStr)]
public String pDatatype;
public IntPtr pDevMode;
[MarshalAs(UnmanagedType.I4)]
public int DesiredAccess;
};
[DllImport("winspool.Drv", EntryPoint = "OpenPrinter", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall),
SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPTStr)]
string printerName,
out IntPtr phPrinter,
ref structPrinterDefaults pd);
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = false,
CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool ClosePrinter(IntPtr phPrinter);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct structSize
{
public Int32 width;
public Int32 height;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct structRect
{
public Int32 left;
public Int32 top;
public Int32 right;
public Int32 bottom;
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
internal struct FormInfo1
{
[FieldOffset(0), MarshalAs(UnmanagedType.I4)]
public uint Flags;
[FieldOffset(4), MarshalAs(UnmanagedType.LPWStr)]
public String pName;
[FieldOffset(8)]
public structSize Size;
[FieldOffset(16)]
public structRect ImageableArea;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi/* changed from CharSet=CharSet.Auto */)]
internal struct structDevMode
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public String
dmDeviceName;
[MarshalAs(UnmanagedType.U2)]
public short dmSpecVersion;
[MarshalAs(UnmanagedType.U2)]
public short dmDriverVersion;
[MarshalAs(UnmanagedType.U2)]
public short dmSize;
[MarshalAs(UnmanagedType.U2)]
public short dmDriverExtra;
[MarshalAs(UnmanagedType.U4)]
public int dmFields;
[MarshalAs(UnmanagedType.I2)]
public short dmOrientation;
[MarshalAs(UnmanagedType.I2)]
public short dmPaperSize;
[MarshalAs(UnmanagedType.I2)]
public short dmPaperLength;
[MarshalAs(UnmanagedType.I2)]
public short dmPaperWidth;
[MarshalAs(UnmanagedType.I2)]
public short dmScale;
[MarshalAs(UnmanagedType.I2)]
public short dmCopies;
[MarshalAs(UnmanagedType.I2)]
public short dmDefaultSource;
[MarshalAs(UnmanagedType.I2)]
public short dmPrintQuality;
[MarshalAs(UnmanagedType.I2)]
public short dmColor;
[MarshalAs(UnmanagedType.I2)]
public short dmDuplex;
[MarshalAs(UnmanagedType.I2)]
public short dmYResolution;
[MarshalAs(UnmanagedType.I2)]
public short dmTTOption;
[MarshalAs(UnmanagedType.I2)]
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public String dmFormName;
[MarshalAs(UnmanagedType.U2)]
public short dmLogPixels;
[MarshalAs(UnmanagedType.U4)]
public int dmBitsPerPel;
[MarshalAs(UnmanagedType.U4)]
public int dmPelsWidth;
[MarshalAs(UnmanagedType.U4)]
public int dmPelsHeight;
[MarshalAs(UnmanagedType.U4)]
public int dmNup;
[MarshalAs(UnmanagedType.U4)]
public int dmDisplayFrequency;
[MarshalAs(UnmanagedType.U4)]
public int dmICMMethod;
[MarshalAs(UnmanagedType.U4)]
public int dmICMIntent;
[MarshalAs(UnmanagedType.U4)]
public int dmMediaType;
[MarshalAs(UnmanagedType.U4)]
public int dmDitherType;
[MarshalAs(UnmanagedType.U4)]
public int dmReserved1;
[MarshalAs(UnmanagedType.U4)]
public int dmReserved2;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct PRINTER_INFO_9
{
public IntPtr pDevMode;
}
[DllImport("winspool.Drv", EntryPoint = "AddFormW", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool AddForm(
IntPtr phPrinter,
[MarshalAs(UnmanagedType.I4)] int level,
ref FormInfo1 form);
[DllImport("winspool.Drv", EntryPoint = "SetForm", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = false,
CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool SetForm(IntPtr phPrinter, string paperName,
[MarshalAs(UnmanagedType.I4)] int level, ref FormInfo1 form);
[DllImport("winspool.Drv", EntryPoint = "DeleteForm", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall),
SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool DeleteForm(
IntPtr phPrinter,
[MarshalAs(UnmanagedType.LPTStr)] string pName);
[DllImport("kernel32.dll", EntryPoint = "GetLastError", SetLastError = false,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall),
SuppressUnmanagedCodeSecurityAttribute()]
internal static extern Int32 GetLastError();
[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 structDevMode 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 structDevMode
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 = "SetPrinterA", SetLastError = true,
CharSet = CharSet.Auto, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool SetPrinter(
IntPtr hPrinter,
[MarshalAs(UnmanagedType.I4)] int level,
IntPtr pPrinter,
[MarshalAs(UnmanagedType.I4)] int command);
/*
LONG DocumentProperties(
HWND hWnd, // handle to parent window
HANDLE hPrinter, // handle to printer object
LPTSTR pDeviceName, // device name
PDEVMODE pDevModeOutput, // modified device mode
PDEVMODE pDevModeInput, // original device mode
DWORD fMode // mode options
);
*/
[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 pDeviceName /* changed from String to string */,
IntPtr pDevModeOutput,
IntPtr pDevModeInput,
int fMode
);
[DllImport("winspool.Drv", EntryPoint = "GetPrinterA", SetLastError = true,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool GetPrinter(
IntPtr hPrinter,
int dwLevel /* changed type from Int32 */,
IntPtr pPrinter,
int dwBuf /* chagned from Int32*/,
out int dwNeeded /* changed from Int32*/
);
// SendMessageTimeout tools
[Flags]
public enum SendMessageTimeoutFlags : uint
{
SMTO_NORMAL = 0x0000,
SMTO_BLOCK = 0x0001,
SMTO_ABORTIFHUNG = 0x0002,
SMTO_NOTIMEOUTIFNOTHUNG = 0x0008
}
const int WM_SETTINGCHANGE = 0x001A;
const int HWND_BROADCAST = 0xffff;
[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
);
public static void AddMjm80MmPaperSizeToDefaultPrinter()
{
AddCustomPaperSizeToDefaultPrinter("MJM 80mm * Receipt Length", 80.1f, 4003.9f);
}
public static void AddMjm104MmPaperSizeToDefaultPrinter()
{
AddCustomPaperSizeToDefaultPrinter("MJM 104mm * Receipt Length", 104.1f, 4003.9f);
}
/// <summary>
/// Adds the printer form to the default printer
/// </summary>
/// <param name="paperName">Name of the printer form</param>
/// <param name="widthMm">Width given in millimeters</param>
/// <param name="heightMm">Height given in millimeters</param>
public static void AddCustomPaperSizeToDefaultPrinter(string paperName, float widthMm, float heightMm)
{
PrintDocument pd = new PrintDocument();
string sPrinterName = pd.PrinterSettings.PrinterName;
AddCustomPaperSize(sPrinterName, paperName, widthMm, heightMm);
}
/// <summary>
/// Add the printer form to a printer
/// </summary>
/// <param name="printerName">The printer name</param>
/// <param name="paperName">Name of the printer form</param>
/// <param name="widthMm">Width given in millimeters</param>
/// <param name="heightMm">Height given in millimeters</param>
public static void AddCustomPaperSize(string printerName, string paperName, float
widthMm, float heightMm)
{
if (PlatformID.Win32NT == Environment.OSVersion.Platform)
{
// The code to add a custom paper size is different for Windows NT then it is
// for previous versions of windows
const int PRINTER_ACCESS_USE = 0x00000008;
const int PRINTER_ACCESS_ADMINISTER = 0x00000004;
const int FORM_PRINTER = 0x00000002;
structPrinterDefaults defaults = new structPrinterDefaults();
defaults.pDatatype = null;
defaults.pDevMode = IntPtr.Zero;
defaults.DesiredAccess = PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE;
IntPtr hPrinter = IntPtr.Zero;
// Open the printer.
if (OpenPrinter(printerName, out hPrinter, ref defaults))
{
try
{
// delete the form incase it already exists
DeleteForm(hPrinter, paperName);
// create and initialize the FORM_INFO_1 structure
FormInfo1 formInfo = new FormInfo1();
formInfo.Flags = 0;
formInfo.pName = paperName;
// all sizes in 1000ths of millimeters
formInfo.Size.width = (int)(widthMm * 1000.0);
formInfo.Size.height = (int)(heightMm * 1000.0);
formInfo.ImageableArea.left = 0;
formInfo.ImageableArea.right = formInfo.Size.width;
formInfo.ImageableArea.top = 0;
formInfo.ImageableArea.bottom = formInfo.Size.height;
if (!AddForm(hPrinter, 1, ref formInfo))
{
StringBuilder strBuilder = new StringBuilder();
strBuilder.AppendFormat("Failed to add the custom paper size {0} to the printer {1}, System error number: {2}",
paperName, printerName, GetLastError());
throw new ApplicationException(strBuilder.ToString());
}
else
{
bool x = SetForm(hPrinter, paperName, 1, ref formInfo);
}
// INIT
const int DM_OUT_BUFFER = 2;
const int DM_IN_BUFFER = 8;
structDevMode devMode = new structDevMode();
IntPtr hPrinterInfo, hDummy;
PRINTER_INFO_9 printerInfo;
printerInfo.pDevMode = IntPtr.Zero;
int iPrinterInfoSize, iDummyInt;
// GET THE SIZE OF THE DEV_MODE BUFFER
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.");
// ALLOCATE THE BUFFER
IntPtr hDevMode = Marshal.AllocCoTaskMem(iDevModeSize + 100);
// GET A POINTER TO THE DEV_MODE BUFFER
int iRet = DocumentProperties(IntPtr.Zero, hPrinter, printerName, hDevMode, IntPtr.Zero, DM_OUT_BUFFER);
if (iRet < 0)
throw new ApplicationException("Cannot get the DEVMODE structure.");
// FILL THE DEV_MODE STRUCTURE
devMode = (structDevMode)Marshal.PtrToStructure(hDevMode, devMode.GetType());
// SET THE FORM NAME FIELDS TO INDICATE THAT THIS FIELD WILL BE MODIFIED
devMode.dmFields = 0x10000; // DM_FORMNAME
// SET THE FORM NAME
devMode.dmFormName = paperName;
// PUT THE DEV_MODE STRUCTURE BACK INTO THE POINTER
Marshal.StructureToPtr(devMode, hDevMode, true);
// MERGE THE NEW CHAGES WITH THE OLD
iRet = DocumentProperties(IntPtr.Zero, hPrinter, printerName,
printerInfo.pDevMode, printerInfo.pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER);
if (iRet < 0)
throw new ApplicationException("Unable to set the orientation setting for this printer.");
// GET THE PRINTER INFO SIZE
GetPrinter(hPrinter, 9, IntPtr.Zero, 0, out iPrinterInfoSize);
if (iPrinterInfoSize == 0)
throw new ApplicationException("GetPrinter failed. Couldn't get the # bytes needed for shared PRINTER_INFO_9 structure");
// ALLOCATE THE BUFFER
hPrinterInfo = Marshal.AllocCoTaskMem(iPrinterInfoSize + 100);
// GET A POINTER TO THE PRINTER INFO BUFFER
bool bSuccess = GetPrinter(hPrinter, 9, hPrinterInfo, iPrinterInfoSize, out iDummyInt);
if (!bSuccess)
throw new ApplicationException("GetPrinter failed. Couldn't get the shared PRINTER_INFO_9 structure");
// FILL THE PRINTER INFO STRUCTURE
printerInfo = (PRINTER_INFO_9)Marshal.PtrToStructure(hPrinterInfo, printerInfo.GetType());
printerInfo.pDevMode = hDevMode;
// GET A POINTER TO THE PRINTER INFO STRUCTURE
Marshal.StructureToPtr(printerInfo, hPrinterInfo, true);
// SET THE PRINTER SETTINGS
bSuccess = SetPrinter(hPrinter, 9, hPrinterInfo, 0);
if (!bSuccess)
throw new Win32Exception(Marshal.GetLastWin32Error(), "SetPrinter() failed. Couldn't set the printer settings");
// Tell all open programs that this change occurred.
SendMessageTimeout(new IntPtr(HWND_BROADCAST), WM_SETTINGCHANGE, IntPtr.Zero, IntPtr.Zero, CustomPrintForm.SendMessageTimeoutFlags.SMTO_NORMAL, 1000, out hDummy);
}
finally
{
ClosePrinter(hPrinter);
}
}
else
{
StringBuilder strBuilder = new StringBuilder();
strBuilder.AppendFormat("Failed to open the {0} printer, System error number: {1}",
printerName, GetLastError());
throw new ApplicationException(strBuilder.ToString());
}
}
else
{
structDevMode pDevMode = new structDevMode();
IntPtr hDC = CreateDC(null, printerName, null, ref pDevMode);
if (hDC != IntPtr.Zero)
{
const long DM_PAPERSIZE = 0x00000002L;
const long DM_PAPERLENGTH = 0x00000004L;
const long DM_PAPERWIDTH = 0x00000008L;
pDevMode.dmFields = (int)(DM_PAPERSIZE | DM_PAPERWIDTH | DM_PAPERLENGTH);
pDevMode.dmPaperSize = 256;
pDevMode.dmPaperWidth = (short)(widthMm * 1000.0);
pDevMode.dmPaperLength = (short)(heightMm * 1000.0);
ResetDC(hDC, ref pDevMode);
DeleteDC(hDC);
}
}
}
}
}
需要帮助解决这个问题。
您的代码几乎完美无缺(需要在 64 位模式下工作)并且完成了预期的工作:
然而,好消息到此为止。您正在使用的 api 直接与打印机驱动程序对话,它负责确保您的 DEVMODE 更改生效。这适用于 XPS 打印机驱动程序,但不适用于许多其他类型的驱动程序。好像惠普的驱动我也试过了
您所做的一切都会在注册表中立即显示 side-effect。你可以用Regedit.exe看到它。这是 double-check 您的代码的好方法。要看到它,您需要停止尝试,因为打印机驱动程序不会 co-operate。你想看的按键:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Forms。此键列出您添加的表单。你应该不会有那个问题。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Forms\MJM 80mm * 收据长度,"FormKeyword" 值。记下来,就是打印机选择你的表格的"keyword"
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Printers\printername、"Default DevMode"值。这是在您调用 SetPrinter() 时写入的。您可以查看该值的十六进制转储。您在上一步中记下的 FormKeyword 在偏移量 0x348
处可见
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Printers\printername\DsDriver,printMediaSupported 值。对此不完全确定,但应该显示纸张尺寸列表,并且您的自定义表单应该在那里可见。
不好意思,打印机很烂。
x64 使用
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
internal struct FormInfo1
{
[FieldOffset(0), MarshalAs(UnmanagedType.I4)]
public uint Flags;
[FieldOffset(8), MarshalAs(UnmanagedType.LPWStr)]
public String pName;
[FieldOffset(16)]
public structSize Size;
[FieldOffset(24)]
public structRect ImageableArea;
};
感谢Nilesh 的代码和Hans 的注册信息,我的要求是通过c# 程序为特定打印机设置默认页面大小,然后打开网络浏览器打印特定网页。
现在我尝试添加我的自定义页面表单,并将 dmFormName 设置为默认值。然后我重新获取 devmode struct , dmFormName 是我更改的,但是当我打开记事本或其他应用程序并尝试打印一些东西时,我看到默认的页面大小不是我设置的。
我也尝试删除所有未使用的pagesizes,这样默认只有一个,但只能删除自己添加的pagesizes。
PS:我做了一些代码重构如下:
internal class PrinterPagaSize
{
public void DeleteAllPrintForm(string printerName)
{
structPrinterDefaults defaults = InitPrinterDefaults();
IntPtr hPrinter = IntPtr.Zero;
if (OpenPrinter(printerName, out hPrinter, ref defaults))
{
try
{
var printerSettings = PrinterSelector.DefaultPrinterSettings;
foreach (PaperSize ps in printerSettings.PaperSizes)
{
bool ret = DeleteForm(hPrinter, ps.PaperName);
Debug.WriteLine("delete ret:" + ret.ToString());
}
}
finally
{
ClosePrinter(hPrinter);
}
}
}
public PaperSize GetPrintForm(string printerName, string paperName)
{
PaperSize paper = null;
//var printer = new System.Drawing.Printing.PrinterSettings {PrinterName = printerName};
var printer = PrinterSelector.DefaultPrinterSettings;
foreach (PaperSize ps in printer.PaperSizes)
{
if (ps.PaperName.ToLower() == paperName.ToLower())
{
paper = ps;
break;
}
}
return paper;
}
/// <summary>
/// Add the printer form to a printer
/// </summary>
/// <param name="printerName">The printer name</param>
/// <param name="paperName">Name of the printer form</param>
/// <param name="widthMm">Width given in millimeters</param>
/// <param name="heightMm">Height given in millimeters</param>
public void AddCustomPaperSize(string printerName, string paperName, float
width, float height)
{
if (PlatformID.Win32NT == Environment.OSVersion.Platform)
{
// The code to add a custom paper size is different for Windows NT then it is
// for previous versions of windows
structPrinterDefaults defaults = InitPrinterDefaults();
IntPtr hPrinter = IntPtr.Zero;
// Open the printer.
if (OpenPrinter(printerName, out hPrinter, ref defaults))
{
try
{
// delete the form incase it already exists
DeleteForm(hPrinter, paperName);
// create and initialize the FORM_INFO_1 structure
FormInfo1 formInfo = new FormInfo1();
formInfo.Flags = 0;
formInfo.pName = paperName;
// all sizes in 1000ths of millimeters
formInfo.Size.width = (int)(width * 100.0);
formInfo.Size.height = (int)(height * 100.0);
formInfo.ImageableArea.left = 0;
formInfo.ImageableArea.right = formInfo.Size.width;
formInfo.ImageableArea.top = 0;
formInfo.ImageableArea.bottom = formInfo.Size.height;
if (!AddForm(hPrinter, 1, ref formInfo))
{
StringBuilder strBuilder = new StringBuilder();
strBuilder.AppendFormat(
"Failed to add the custom paper size {0} to the printer {1}, System error number: {2}",
paperName, printerName, GetLastError());
throw new ApplicationException(strBuilder.ToString());
}
else
{
SetForm(hPrinter, paperName, 1, ref formInfo);
}
SetPrinterDevMode(hPrinter, printerName, paperName);
}
finally
{
ClosePrinter(hPrinter);
}
}
else
{
StringBuilder strBuilder = new StringBuilder();
strBuilder.AppendFormat("Failed to open the {0} printer, System error number: {1}",
printerName, GetLastError());
throw new ApplicationException(strBuilder.ToString());
}
}
else
{
structDevMode pDevMode = new structDevMode();
IntPtr hDC = CreateDC(null, printerName, null, ref pDevMode);
if (hDC != IntPtr.Zero)
{
const long DM_PAPERSIZE = 0x00000002L;
const long DM_PAPERLENGTH = 0x00000004L;
const long DM_PAPERWIDTH = 0x00000008L;
pDevMode.dmFields = (int)(DM_PAPERSIZE | DM_PAPERWIDTH | DM_PAPERLENGTH);
pDevMode.dmPaperSize = 256;
pDevMode.dmPaperWidth = (short)(width * 1000.0);
pDevMode.dmPaperLength = (short)(height * 1000.0);
ResetDC(hDC, ref pDevMode);
DeleteDC(hDC);
}
}
}
const int DM_OUT_BUFFER = 2;
const int DM_IN_BUFFER = 8;
private void SetPrinterDevMode(IntPtr hPrinter, string printerName, string paperName)
{
// INIT
structDevMode devMode = new structDevMode();
PRINTER_INFO_9 printerInfo = new PRINTER_INFO_9();
printerInfo.pDevMode = IntPtr.Zero;
IntPtr hDevMode = GetDevMode(hPrinter, printerName, ref devMode);
// SET THE FORM NAME FIELDS TO INDICATE THAT THIS FIELD WILL BE MODIFIED
devMode.dmFields = 0x10000; // DM_FORMNAME
// SET THE FORM NAME
devMode.dmFormName = paperName;
ChangeDevMode(hPrinter, printerName, paperName, devMode, hDevMode, ref printerInfo);
IntPtr hPrinterInfo = GetPrinterInfo(hPrinter);
// FILL THE PRINTER INFO STRUCTURE
printerInfo = (PRINTER_INFO_9)Marshal.PtrToStructure(hPrinterInfo, printerInfo.GetType());
printerInfo.pDevMode = hDevMode;
// GET A POINTER TO THE PRINTER INFO STRUCTURE
Marshal.StructureToPtr(printerInfo, hPrinterInfo, true);
// SET THE PRINTER SETTINGS
bool bSuccess = SetPrinter(hPrinter, 9, hPrinterInfo, 0);
if (!bSuccess)
throw new Exception("Set printer failed!");
}
private static IntPtr GetPrinterInfo(IntPtr hPrinter)
{
IntPtr hPrinterInfo;
bool bSuccess = false;
int iPrinterInfoSize, iDummyInt;
// GET THE PRINTER INFO SIZE
GetPrinter(hPrinter, 9, IntPtr.Zero, 0, out iPrinterInfoSize);
if (iPrinterInfoSize == 0)
throw new ApplicationException(
"GetPrinter failed. Couldn't get the # bytes needed for shared PRINTER_INFO_9 structure");
// ALLOCATE THE BUFFER
hPrinterInfo = Marshal.AllocCoTaskMem(iPrinterInfoSize + 100);
// GET A POINTER TO THE PRINTER INFO BUFFER
bSuccess = GetPrinter(hPrinter, 9, hPrinterInfo, iPrinterInfoSize, out iDummyInt);
if (!bSuccess)
throw new ApplicationException(
"GetPrinter failed. Couldn't get the shared PRINTER_INFO_9 structure");
return hPrinterInfo;
}
private static void ChangeDevMode(IntPtr hPrinter, string printerName, string paperName, structDevMode devMode, IntPtr hDevMode, ref PRINTER_INFO_9 printerInfo)
{
// PUT THE DEV_MODE STRUCTURE BACK INTO THE POINTER
Marshal.StructureToPtr(devMode, hDevMode, true);
// MERGE THE NEW CHAGES WITH THE OLD
int iRet = DocumentProperties(IntPtr.Zero, hPrinter, printerName,
printerInfo.pDevMode, printerInfo.pDevMode, DM_IN_BUFFER | DM_OUT_BUFFER);
if (iRet < 0)
throw new ApplicationException("Unable to set the orientation setting for this printer.");
}
private static IntPtr GetDevMode(IntPtr hPrinter, string printerName, ref structDevMode devMode)
{
// GET THE SIZE OF THE DEV_MODE BUFFER
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.");
// ALLOCATE THE BUFFER
IntPtr hDevMode = Marshal.AllocCoTaskMem(iDevModeSize + 100);
// GET A POINTER TO THE DEV_MODE BUFFER
int iRet = DocumentProperties(IntPtr.Zero, hPrinter, printerName, hDevMode, IntPtr.Zero,
DM_OUT_BUFFER);
if (iRet < 0)
throw new ApplicationException("Cannot get the DEVMODE structure.");
// FILL THE DEV_MODE STRUCTURE
devMode = (structDevMode)Marshal.PtrToStructure(hDevMode, devMode.GetType());
return hDevMode;
}
private static structPrinterDefaults InitPrinterDefaults()
{
const int PRINTER_ACCESS_USE = 0x00000008;
const int PRINTER_ACCESS_ADMINISTER = 0x00000004;
structPrinterDefaults defaults = new structPrinterDefaults();
defaults.pDatatype = null;
defaults.pDevMode = IntPtr.Zero;
defaults.DesiredAccess = PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE;
return defaults;
}
#region Win API
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct structPrinterDefaults
{
[MarshalAs(UnmanagedType.LPTStr)]
public String pDatatype;
public IntPtr pDevMode;
[MarshalAs(UnmanagedType.I4)]
public int DesiredAccess;
};
[DllImport("winspool.Drv", EntryPoint = "OpenPrinter", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall),
SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPTStr)] string printerName,
out IntPtr phPrinter,
ref structPrinterDefaults pd);
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = false,
CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool ClosePrinter(IntPtr phPrinter);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct structSize
{
public Int32 width;
public Int32 height;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct structRect
{
public Int32 left;
public Int32 top;
public Int32 right;
public Int32 bottom;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct FormInfo1
{
[MarshalAs(UnmanagedType.I4)]
public int Flags;
[MarshalAs(UnmanagedType.LPTStr)]
public String pName;
public structSize Size;
public structRect ImageableArea;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi /* changed from CharSet=CharSet.Auto */)]
internal struct structDevMode
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public String
dmDeviceName;
[MarshalAs(UnmanagedType.U2)]
public short dmSpecVersion;
[MarshalAs(UnmanagedType.U2)]
public short dmDriverVersion;
[MarshalAs(UnmanagedType.U2)]
public short dmSize;
[MarshalAs(UnmanagedType.U2)]
public short dmDriverExtra;
[MarshalAs(UnmanagedType.U4)]
public int dmFields;
[MarshalAs(UnmanagedType.I2)]
public short dmOrientation;
[MarshalAs(UnmanagedType.I2)]
public short dmPaperSize;
[MarshalAs(UnmanagedType.I2)]
public short dmPaperLength;
[MarshalAs(UnmanagedType.I2)]
public short dmPaperWidth;
[MarshalAs(UnmanagedType.I2)]
public short dmScale;
[MarshalAs(UnmanagedType.I2)]
public short dmCopies;
[MarshalAs(UnmanagedType.I2)]
public short dmDefaultSource;
[MarshalAs(UnmanagedType.I2)]
public short dmPrintQuality;
[MarshalAs(UnmanagedType.I2)]
public short dmColor;
[MarshalAs(UnmanagedType.I2)]
public short dmDuplex;
[MarshalAs(UnmanagedType.I2)]
public short dmYResolution;
[MarshalAs(UnmanagedType.I2)]
public short dmTTOption;
[MarshalAs(UnmanagedType.I2)]
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public String dmFormName;
[MarshalAs(UnmanagedType.U2)]
public short dmLogPixels;
[MarshalAs(UnmanagedType.U4)]
public int dmBitsPerPel;
[MarshalAs(UnmanagedType.U4)]
public int dmPelsWidth;
[MarshalAs(UnmanagedType.U4)]
public int dmPelsHeight;
[MarshalAs(UnmanagedType.U4)]
public int dmNup;
[MarshalAs(UnmanagedType.U4)]
public int dmDisplayFrequency;
[MarshalAs(UnmanagedType.U4)]
public int dmICMMethod;
[MarshalAs(UnmanagedType.U4)]
public int dmICMIntent;
[MarshalAs(UnmanagedType.U4)]
public int dmMediaType;
[MarshalAs(UnmanagedType.U4)]
public int dmDitherType;
[MarshalAs(UnmanagedType.U4)]
public int dmReserved1;
[MarshalAs(UnmanagedType.U4)]
public int dmReserved2;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct PRINTER_INFO_9
{
public IntPtr pDevMode;
}
[DllImport("winspool.Drv", EntryPoint = "AddFormW", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool AddForm(
IntPtr phPrinter,
[MarshalAs(UnmanagedType.I4)] int level,
ref FormInfo1 form);
[DllImport("winspool.Drv", EntryPoint = "SetForm", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = false,
CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool SetForm(IntPtr phPrinter, string paperName,
[MarshalAs(UnmanagedType.I4)] int level, ref FormInfo1 form);
[DllImport("winspool.Drv", EntryPoint = "DeleteForm", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = false, CallingConvention = CallingConvention.StdCall),
SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool DeleteForm(
IntPtr phPrinter,
[MarshalAs(UnmanagedType.LPTStr)] string pName);
[DllImport("kernel32.dll", EntryPoint = "GetLastError", SetLastError = false,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall),
SuppressUnmanagedCodeSecurityAttribute()]
internal static extern Int32 GetLastError();
[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 structDevMode 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 structDevMode
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 = "SetPrinterA", SetLastError = true,
CharSet = CharSet.Auto, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall), SuppressUnmanagedCodeSecurityAttribute()]
internal static extern bool SetPrinter(
IntPtr hPrinter,
[MarshalAs(UnmanagedType.I4)] int level,
IntPtr pPrinter,
[MarshalAs(UnmanagedType.I4)] int command);
/*
LONG DocumentProperties(
HWND hWnd, // handle to parent window
HANDLE hPrinter, // handle to printer object
LPTSTR pDeviceName, // device name
PDEVMODE pDevModeOutput, // modified device mode
PDEVMODE pDevModeInput, // original device mode
DWORD fMode // mode options
);
*/
[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 pDeviceName /* changed from String to string */,
IntPtr pDevModeOutput,
IntPtr pDevModeInput,
int fMode
);
[DllImport("winspool.Drv", EntryPoint = "GetPrinterA", SetLastError = true,
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool GetPrinter(
IntPtr hPrinter,
int dwLevel /* changed type from Int32 */,
IntPtr pPrinter,
int dwBuf /* chagned from Int32*/,
out int dwNeeded /* changed from Int32*/
);
// SendMessageTimeout tools
[Flags]
public enum SendMessageTimeoutFlags : uint
{
SMTO_NORMAL = 0x0000,
SMTO_BLOCK = 0x0001,
SMTO_ABORTIFHUNG = 0x0002,
SMTO_NOTIMEOUTIFNOTHUNG = 0x0008
}
private const int WM_SETTINGCHANGE = 0x001A;
private const int HWND_BROADCAST = 0xffff;
[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
}
我只是使用类似的代码将特殊纸张尺寸添加到我们的自定义 windows 打印机驱动程序中。似乎有时它不起作用,但原因是打印机的驱动程序 GPD 文件。如果此文件中不存在 CUSTOMIZE 特殊部分,打印机将永远不会接受任何自定义纸张尺寸。您可以使用标准 windows 程序轻松检查将自定义纸张添加到任何打印机。
*Option: CUSTOMSIZE
{
*rcNameID: =USER_DEFINED_SIZE_DISPLAY
*MinSize: PAIR(100, 100)
*MaxSize: PAIR(4026, 11340)
*TopMargin: 0
*BottomMargin: 0
*MaxPrintableWidth: 4026
*MinLeftMargin: 0
*CenterPrintable?: FALSE
*Command: CmdSelect
{
*Order: DOC_SETUP.10
*Cmd: ""
}
}