Sas*_*sha 3 .net printing duplex tray office-automation
我们有一个管理打印文档的项目.起初我想知道为什么不能在一个地方设置打印选项.例如,可以使用MS Word自动化完成第一页和其他页面的打印机托盘选择:
var doc = _applicationObject.Documents.OpenNoRepairDialog(FileName: ref sourceFile, ReadOnly: ref readOnly,
AddToRecentFiles: ref addToRecentFiles,
Visible: ref visible);
doc.PageSetup.FirstPageTray = (WdPaperTray) firstPageTrayCode;
doc.PageSetup.OtherPagesTray = (WdPaperTray) otherPagesTrayCode;
_applicationObject.ActivePrinter = printerPath;
doc.Activate();
_applicationObject.PrintOut(Background: ref backgroundPrint, FileName: sourceFile);
doc.Close(ref saveChanges, ref _missing, ref _missing);
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,打印机托盘被指定为整数,因为某些打印机没有托盘的标准值(我们遇到了HP的问题 - 这里描述的托盘代码).所以我们首先使用代码检索托盘打印机的内容:
var setting = new PrinterSettings();
setting.PrinterName = myPrinterName;
foreach (PaperSource tray in setting.PaperSources)
{
Console.WriteLine("\t{0}: #{1}", tray.SourceName, tray.RawKind);
}
Run Code Online (Sandbox Code Playgroud)
这段代码没有任何问题.
但是这里没有办法指定双面打印和装订选项.双面打印可以做到的,使用驱动程序功能OpenPrinter和SetPrinter,就像描述这里的以及和微软推荐此论坛主题. Staple完全不清楚,如果有人知道如何实现这个,请告诉我.使用Stapling枚举,就像在这篇MSDN文章中一样没用,因为它需要自定义呈现要打印的文档.
我描述了这种情况以及零件的实施方式.这在我们的环境中运行良好:Windows Server 2008 R2,MS Office 2010 x32,打印机HP LaserJet P2055和Ricoh Nashuatec DSm635.使用原生和通用PCL6/PCL5e驱动程序进行测试:双工和托盘选择按预期工作.
但在将应用程序部署到客户端后,打印机(HP LaserJet 4250和Ricoh Aficio MP C7501)始终从默认托盘打印并且没有双面打印.尝试了几个不同的驱动程序,结果完全相同.
在这两种环境中,打印机都是网络打 因此,为了使它们应用双工设置,使用打印机驱动程序,我们需要在服务器上安装本地驱动程序并制作本地打印机,正如我在这个支持论坛帖子上推荐的Microsoft .
虽然使用的环境和打印机看起来非常相似,但其中一个不起作用.任何帮助将受到高度赞赏.
In case someone else needs it, I came up with a workaround, based on storing printer settings memory block in a binary file and then restoring it. The idea was described in this blog post, but it didn't work for me when simply copy-pasted (it worked only for some drivers and for some settings while other printing options were ignored).
So I remade it a bit so that now it can support all settings I've tried on any printer (with compatible driver) I've tested. Of course if you use driver of another printer for example it won't work.
The disadvantage of thi approach is of course that you should first set default printer preferences (in Control Panel) to what you need. That isn't always possible of course, but at least in some cases it can help.
因此,测试工具的完整源代码能够将打印机设置存储到文件中,再次将此文件加载到打印机中并使用指定的设置文件打印文档:
using System;
using System.Collections.Generic;
using System.Drawing.Printing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Office.Interop.Word;
namespace PrintAdvancedTest
{
[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_DEFAULTS
{
public int pDatatype;
public int pDevMode;
public int DesiredAccess;
}
[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_INFO_2
{
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pServerName;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pPrinterName;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pShareName;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pPortName;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pDriverName;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pComment;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pLocation;
public IntPtr pDevMode;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pSepFile;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pPrintProcessor;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pDatatype;
[MarshalAs(UnmanagedType.LPStr)]
public readonly string pParameters;
public IntPtr pSecurityDescriptor;
public readonly Int32 Attributes;
public readonly Int32 Priority;
public readonly Int32 DefaultPriority;
public readonly Int32 StartTime;
public readonly Int32 UntilTime;
public readonly Int32 Status;
public readonly Int32 cJobs;
public readonly Int32 AveragePPM;
}
public class PrintSettings
{
private const short CCDEVICENAME = 32;
private const short CCFORMNAME = 32;
//Constants for DEVMODE
// Constants for DocumentProperties
private const int DM_MODIFY = 8;
private const int DM_COPY = 2;
private const int DM_IN_BUFFER = DM_MODIFY;
private const int DM_OUT_BUFFER = DM_COPY;
// const intants for dmOrientation
private const int DMORIENT_PORTRAIT = 1;
private const int DMORIENT_LANDSCAPE = 2;
// const intants for dmPrintQuality
private const int DMRES_DRAFT = (-1);
private const int DMRES_HIGH = (-4);
private const int DMRES_LOW = (-2);
private const int DMRES_MEDIUM = (-3);
// const intants for dmTTOption
private const int DMTT_BITMAP = 1;
private const int DMTT_DOWNLOAD = 2;
private const int DMTT_DOWNLOAD_OUTLINE = 4;
private const int DMTT_SUBDEV = 3;
// const intants for dmColor
private const int DMCOLOR_COLOR = 2;
private const int DMCOLOR_MONOCHROME = 1;
// const intants for dmCollate
private const int DMCOLLATE_FALSE = 0;
private const int DMCOLLATE_TRUE = 1;
// const intants for dmDuplex
private const int DMDUP_HORIZONTAL = 3;
private const int DMDUP_SIMPLEX = 1;
private const int DMDUP_VERTICAL = 2;
//const for security access
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);
/* field selection bits */
private const int DM_ORIENTATION = 0x00000001;
private const int DM_PAPERSIZE = 0x00000002;
private const int DM_PAPERLENGTH = 0x00000004;
private const int DM_PAPERWIDTH = 0x00000008;
private const int DM_SCALE = 0x00000010;
private const int DM_POSITION = 0x00000020;
private const int DM_NUP = 0x00000040;
private const int DM_DISPLAYORIENTATION = 0x00000080;
private const int DM_COPIES = 0x00000100;
private const int DM_DEFAULTSOURCE = 0x00000200;
private const int DM_PRINTQUALITY = 0x00000400;
private const int DM_COLOR = 0x00000800;
private const int DM_DUPLEX = 0x00001000;
private const int DM_YRESOLUTION = 0x00002000;
private const int DM_TTOPTION = 0x00004000;
private const int DM_COLLATE = 0x00008000;
private const int DM_FORMNAME = 0x00010000;
private const int DM_LOGPIXELS = 0x00020000;
private const int DM_BITSPERPEL = 0x00040000;
private const int DM_PELSWIDTH = 0x00080000;
private const int DM_PELSHEIGHT = 0x00100000;
private const int DM_DISPLAYFLAGS = 0x00200000;
private const int DM_DISPLAYFREQUENCY = 0x00400000;
private const int DM_ICMMETHOD = 0x00800000;
private const int DM_ICMINTENT = 0x01000000;
private const int DM_MEDIATYPE = 0x02000000;
private const int DM_DITHERTYPE = 0x04000000;
private const int DM_PANNINGWIDTH = 0x08000000;
private const int DM_PANNINGHEIGHT = 0x10000000;
private const int DM_DISPLAYFIXEDOUTPUT = 0x20000000;
[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;
}
static void Main(string[] args)
{
Dictionary<string, Action> commands = new Dictionary<string, Action>
{
{"save", PrinterPreferencesSave},
{"print", PrinterPreferencesPrint},
{"set", PrinterPreferencesSet},
{"info", PrinterInfo}
};
while (true)
{
Console.Write("Command ({0}): ", string.Join(", ", commands.Keys));
string command = Console.ReadLine();
Action action;
if (!commands.TryGetValue(command, out action))
{
Console.WriteLine("Invalid command");
}
else
{
action();
}
}
}
static void PrinterPreferencesSave()
{
Console.Write("Printer name: ");
string printerName = Console.ReadLine();
Console.Write("Settings file path format: ");
string SettingsFileNameFormat = Console.ReadLine();
string testName;
while (true)
{
Console.Write("SAVE: Settings set name: ");
testName = Console.ReadLine();
if (testName == "end")
{
break;
}
getDevMode(printerName, string.Format(SettingsFileNameFormat, testName));
}
}
static void PrinterPreferencesPrint()
{
Console.Write("Printer name: ");
string printerName = Console.ReadLine();
Console.Write("Settings file path format: ");
string SettingsFileNameFormat = Console.ReadLine();
Console.Write("Document to print: ");
string docToPrintPath = Console.ReadLine();
string testName;
while (true)
{
Console.Write("PRINT: Settings set name: ");
testName = Console.ReadLine();
if (testName == "end")
{
break;
}
string filePath = string.Format(SettingsFileNameFormat, testName);
if (!File.Exists(filePath))
{
Console.WriteLine("File {0} not exists", filePath);
return;
}
var success = setDevMode(printerName, filePath);
if (success)
{
PrintWordDocument(docToPrintPath, printerName);
}
}
}
static void PrinterPreferencesSet()
{
Console.Write("Printer name: ");
string printerName = Console.ReadLine();
Console.Write("Settings file path format: ");
string SettingsFileNameFormat = Console.ReadLine();
string testName;
while (true)
{
Console.Write("SET: Settings set name: ");
testName = Console.ReadLine();
if (testName == "end")
{
break;
}
string filePath = string.Format(SettingsFileNameFormat, testName);
if (!File.Exists(filePath))
{
Console.WriteLine("File {0} not exists", filePath);
return;
}
var success = setDevMode(printerName, filePath);
if(!success)
{
Console.WriteLine("Failed");
}
}
}
private static void PrinterInfo()
{
Console.Write("Printer name: ");
string printerName = Console.ReadLine();
IntPtr hDevMode; // handle to the DEVMODE
IntPtr pDevMode; // pointer to the DEVMODE
DEVMODE devMode; // the actual DEVMODE structure
//var printController = new StandardPrintController();
PrinterSettings printerSettings = new PrinterSettings();
printerSettings.PrinterName = printerName;
// Get a handle to a DEVMODE for the default printer settings
hDevMode = printerSettings.GetHdevmode(printerSettings.DefaultPageSettings);
// Obtain a lock on the handle and get an actual pointer so Windows won't
// move it around while we're futzing with it
pDevMode = GlobalLock(hDevMode);
// Marshal the memory at that pointer into our P/Invoke version of DEVMODE
devMode = (DEVMODE)Marshal.PtrToStructure(pDevMode, typeof(DEVMODE));
Dictionary<string, int> dmConstants = new Dictionary<string, int>
{
{"DM_ORIENTATION", 0x00000001},
{"DM_PAPERSIZE", 0x00000002},
{"DM_PAPERLENGTH", 0x00000004},
{"DM_PAPERWIDTH", 0x00000008},
{"DM_SCALE", 0x00000010},
{"DM_POSITION", 0x00000020},
{"DM_NUP", 0x00000040},
{"DM_DISPLAYORIENTATION", 0x00000080},
{"DM_COPIES", 0x00000100},
{"DM_DEFAULTSOURCE", 0x00000200},
{"DM_PRINTQUALITY", 0x00000400},
{"DM_COLOR", 0x00000800},
{"DM_DUPLEX", 0x00001000},
{"DM_YRESOLUTION", 0x00002000},
{"DM_TTOPTION", 0x00004000},
{"DM_COLLATE", 0x00008000},
{"DM_FORMNAME", 0x00010000},
{"DM_LOGPIXELS", 0x00020000},
{"DM_BITSPERPEL", 0x00040000},
{"DM_PELSWIDTH", 0x00080000},
{"DM_PELSHEIGHT", 0x00100000},
{"DM_DISPLAYFLAGS", 0x00200000},
{"DM_DISPLAYFREQUENCY", 0x00400000},
{"DM_ICMMETHOD", 0x00800000},
{"DM_ICMINTENT", 0x01000000},
{"DM_MEDIATYPE", 0x02000000},
{"DM_DITHERTYPE", 0x04000000},
{"DM_PANNINGWIDTH", 0x08000000},
{"DM_PANNINGHEIGHT", 0x10000000},
{"DM_DISPLAYFIXEDOUTPUT", 0x20000000},
};
Console.WriteLine("Allow set: {0}. Details: {1}", Convert.ToString(devMode.dmFields, 16), string.Join(",", dmConstants.Where(c=>(devMode.dmFields & c.Value)==c.Value).Select(c=>c.Key)));
//private const int DM_POSITION = 0x00000020;
//private const int DM_NUP = 0x00000040;
//private const int DM_DISPLAYORIENTATION = 0x00000080;
//private const int DM_DEFAULTSOURCE = 0x00000200;
//private const int DM_PRINTQUALITY = 0x00000400;
//private const int DM_COLOR = 0x00000800;
//private const int DM_YRESOLUTION = 0x00002000;
//private const int DM_TTOPTION = 0x00004000;
//private const int DM_FORMNAME = 0x00010000;
//private const int DM_LOGPIXELS = 0x00020000;
//private const int DM_BITSPERPEL = 0x00040000;
//private const int DM_PELSWIDTH = 0x00080000;
//private const int DM_PELSHEIGHT = 0x00100000;
//private const int DM_DISPLAYFLAGS = 0x00200000;
//private const int DM_DISPLAYFREQUENCY = 0x00400000;
//private const int DM_ICMMETHOD = 0x00800000;
//private const int DM_ICMINTENT = 0x01000000;
//private const int DM_MEDIATYPE = 0x02000000;
//private const int DM_DITHERTYPE = 0x04000000;
//private const int DM_PANNINGWIDTH = 0x08000000;
//private const int DM_PANNINGHEIGHT = 0x10000000;
//private const int DM_DISPLAYFIXEDOUTPUT = 0x20000000;
WriteDevModePropertyInfo("DeviceName", devMode.dmDeviceName, null);
WriteDevModePropertyInfo("SpecVersion", devMode.dmSpecVersion.ToString(), null);
WriteDevModePropertyInfo("DriverVersion", devMode.dmDriverVersion.ToString(), null);
WriteDevModePropertyInfo("Size", devMode.dmSize.ToString(), null);
WriteDevModePropertyInfo("DriverExtra", devMode.dmDriverExtra.ToString(), null);
WriteDevModePropertyInfo("Orientation", devMode.dmOrientation.ToString(), (devMode.dmFields & DM_ORIENTATION) == DM_ORIENTATION);
WriteDevModePropertyInfo("PaperSize", devMode.dmPaperSize.ToString(), (devMode.dmFields & DM_PAPERSIZE) == DM_PAPERSIZE);
WriteDevModePropertyInfo("PaperLength", devMode.dmPaperLength.ToString(), (devMode.dmFields & DM_PAPERLENGTH) == DM_PAPERLENGTH);
WriteDevModePropertyInfo("PaperWidth", devMode.dmPaperWidth.ToString(), (devMode.dmFields & DM_PAPERWIDTH) == DM_PAPERWIDTH);
WriteDevModePropertyInfo("Scale", devMode.dmScale.ToString(), (devMode.dmFields & DM_SCALE) == DM_SCALE);
WriteDevModePropertyInfo("Copies", devMode.dmCopies.ToString(), (devMode.dmFields & DM_COPIES) == DM_COPIES);
WriteDevModePropertyInfo("Duplex", devMode.dmDuplex.ToString(), (devMode.dmFields & DM_DUPLEX) == DM_DUPLEX);
WriteDevModePropertyInfo("YResolution", devMode.dmYResolution.ToString(), null);
WriteDevModePropertyInfo("TTOption", devMode.dmTTOption.ToString(), null);
WriteDevModePropertyInfo("Collate", devMode.dmCollate.ToString(), (devMode.dmFields & DM_COLLATE) == DM_COLLATE);
WriteDevModePropertyInfo("FormName", devMode.dmFormName.ToString(), null);
WriteDevModePropertyInfo("UnusedPadding", devMode.dmUnusedPadding.ToString(), null);
WriteDevModePropertyInfo("BitsPerPel", devMode.dmBitsPerPel.ToString(), null);
WriteDevModePropertyInfo("PelsWidth", devMode.dmPelsWidth.ToString(), null);
WriteDevModePropertyInfo("PelsHeight", devMode.dmPelsHeight.ToString(), null);
WriteDevModePropertyInfo("DisplayFlags", devMode.dmDisplayFlags.ToString(), null);
WriteDevModePropertyInfo("DisplayFrequency", devMode.dmDisplayFlags.ToString(), null);
}
private static void WriteDevModePropertyInfo(string settingName, string value, bool? allowSet)
{
Console.WriteLine("{0} {1} {2}", allowSet.HasValue ? (allowSet.Value ? "+" : "-") : " ", settingName.PadRight(20, '.'), value);
}
[DllImport("kernel32.dll", ExactSpelling = true)]
public static extern IntPtr GlobalFree(IntPtr handle);
[DllImport("kernel32.dll", ExactSpelling = true)]
public static extern IntPtr GlobalLock(IntPtr handle);
[DllImport("kernel32.dll", ExactSpelling = true)]
public static extern IntPtr GlobalUnlock(IntPtr handle);
[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);
[DllImport("kernel32.dll")]
static extern IntPtr GlobalAlloc(uint uFlags, int dwBytes);
public static void getDevMode(string printerName, string filepath)
{
PRINTER_DEFAULTS PrinterValues = new PRINTER_DEFAULTS();
PrinterValues.pDatatype = 0;
PrinterValues.pDevMode = 0;
PrinterValues.DesiredAccess = PRINTER_ALL_ACCESS;
IntPtr ptrZero = IntPtr.Zero;
IntPtr hPrinter;
IntPtr pDevMode = new IntPtr();
//get printer handle
OpenPrinter(printerName, out hPrinter, ref PrinterValues);
//allocate memory for ptr to devmode, 0 argument retrieves bytes required
int bytes = DocumentProperties(new IntPtr(0), hPrinter, printerName, ptrZero, ref pDevMode, 0);
pDevMode = GlobalAlloc(0, bytes);
//set the pointer
DocumentProperties(new IntPtr(0), hPrinter, printerName, pDevMode, ref ptrZero, DM_OUT_BUFFER);
//write the devMode to a file
using (FileStream fs = new FileStream(filepath, FileMode.Create))
{
for (int i = 0; i < bytes; i++)
{
fs.WriteByte(Marshal.ReadByte(pDevMode, i));
}
}
//free resources
GlobalFree(pDevMode);
ClosePrinter(hPrinter);
}
public static bool setDevMode(string printerName, string filepath)
{
if(!File.Exists(filepath))
{
return false;
}
IntPtr hPrinter;
int bytes = 0;
IntPtr pPInfo;
IntPtr pDevMode;
PRINTER_INFO_2 pInfo = new PRINTER_INFO_2();
PRINTER_DEFAULTS PrinterValues = new PRINTER_DEFAULTS();
PrinterValues.pDatatype = 0;
PrinterValues.pDevMode = 0;
PrinterValues.DesiredAccess = PRINTER_ALL_ACCESS;
//retrieve the devmode from file
using (FileStream fs = new FileStream(filepath, FileMode.Open))
{
int length = Convert.ToInt32(fs.Length);
pDevMode = GlobalAlloc(0, length);
for (int i = 0; i < length; i++)
{
Marshal.WriteByte(pDevMode, i, (byte)fs.ReadByte());
}
}
//get printer handle
OpenPrinter(printerName, out hPrinter, ref PrinterValues);
//get bytes for printer info structure and allocate memory
GetPrinter(hPrinter, 2, IntPtr.Zero, 0, out bytes);
if (bytes == 0)
{
throw new Exception("Get Printer Failed");
}
pPInfo = GlobalAlloc(0, bytes);
//set pointer to printer info
GetPrinter(hPrinter, 2, pPInfo, bytes, out bytes);
//place the printer info structure
pInfo = (PRINTER_INFO_2)Marshal.PtrToStructure(pPInfo, typeof(PRINTER_INFO_2));
//insert the new devmode
pInfo.pDevMode = pDevMode;
pInfo.pSecurityDescriptor = IntPtr.Zero;
//set pointer to new printer info
Marshal.StructureToPtr(pInfo, pPInfo, true);
//update
SetPrinter(hPrinter, 2, pPInfo, 0);
//free resources
GlobalFree(pPInfo);
GlobalFree(pDevMode);
ClosePrinter(hPrinter);
return true;
}
private static void PrintWordDocument(string path, string printerName)
{
object readOnly = true;
object addToRecentFiles = false;
object visible = false;
object backgroundPrint = false;
object saveChanges = false;
object sourceFile = path;
var wordApplication = new Application();
var doc = wordApplication.Documents.OpenNoRepairDialog(FileName: ref sourceFile, ReadOnly: ref readOnly,
AddToRecentFiles: ref addToRecentFiles,
Visible: ref visible);
wordApplication.ActivePrinter = printerName;
doc.Activate();
wordApplication.PrintOut(Background: ref backgroundPrint, FileName: sourceFile);
object _missing = Type.Missing;
doc.Close(ref saveChanges, ref _missing, ref _missing);
}
}
}
Run Code Online (Sandbox Code Playgroud)
更新2018-12-04(5,5年): Marshal.StructureToPtr在这段代码中有一个令人讨厌的罕见问题,今天我终于得到了这个问题的答案(参见Hans Passant的评论).我无法验证这是否真的有效,因为我不再处理该项目,但是如果您尝试使用此代码,则可能需要应用该修复程序.