I am using a windows service and i want to print a .html page when the service will start. I am using this code and it's printing well. But a print dialog box come, how do i print without the print dialog box?
我正在使用Windows服务,我想在服务启动时打印.html页面。我正在使用此代码并且打印效果很好。但是出现了一个打印对话框,如何在没有打印对话框的情况下进行打印?
public void printdoc(string document)
{
Process printjob = new Process();
printjob.StartInfo.FileName = document;
printjob.StartInfo.UseShellExecute = true;
printjob.StartInfo.Verb = "print";
printjob.StartInfo.CreateNoWindow = true;
printjob.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
printjob.Start();
}
Have there any other way to print this without showing the print dialog box.
有没有其他方法可以打印它而不显示打印对话框。
Thanks in advance, Anup Pal
在此先感谢Anup Pal
3 个解决方案
#1
Here's the Holy Grail.
这是圣杯。
Taking advantage of StaTaskScheduler (taken from Parallel Extension Extras (release on Code Gallery)).
利用StaTaskScheduler(取自Parallel Extension Extras(在代码库中发布))。
Features: waits for the printing completion, doesn't show print settings, hopefully reliable.
特点:等待打印完成,不显示打印设置,希望可靠。
Limitations: requires C# 4.0, uses default printer, doesn't allow to change print template
限制:需要C#4.0,使用默认打印机,不允许更改打印模板
TaskScheduler Sta = new StaTaskScheduler(1);
public void PrintHtml(string htmlPath)
{
Task.Factory.StartNew(() => PrintOnStaThread(htmlPath), CancellationToken.None, TaskCreationOptions.None, Sta).Wait();
}
void PrintOnStaThread(string htmlPath)
{
const short PRINT_WAITFORCOMPLETION = 2;
const int OLECMDID_PRINT = 6;
const int OLECMDEXECOPT_DONTPROMPTUSER = 2;
using(var browser = new WebBrowser())
{
browser.Navigate(htmlPath);
while(browser.ReadyState != WebBrowserReadyState.Complete)
Application.DoEvents();
dynamic ie = browser.ActiveXInstance;
ie.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER, PRINT_WAITFORCOMPLETION);
}
}
//--------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: StaTaskScheduler.cs
//
//--------------------------------------------------------------------------
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace System.Threading.Tasks.Schedulers
{
/// <summary>Provides a scheduler that uses STA threads.</summary>
public sealed class StaTaskScheduler : TaskScheduler, IDisposable
{
/// <summary>Stores the queued tasks to be executed by our pool of STA threads.</summary>
private BlockingCollection<Task> _tasks;
/// <summary>The STA threads used by the scheduler.</summary>
private readonly List<Thread> _threads;
/// <summary>Initializes a new instance of the StaTaskScheduler class with the specified concurrency level.</summary>
/// <param name="numberOfThreads">The number of threads that should be created and used by this scheduler.</param>
public StaTaskScheduler(int numberOfThreads)
{
// Validate arguments
if (numberOfThreads < 1) throw new ArgumentOutOfRangeException("concurrencyLevel");
// Initialize the tasks collection
_tasks = new BlockingCollection<Task>();
// Create the threads to be used by this scheduler
_threads = Enumerable.Range(0, numberOfThreads).Select(i =>
{
var thread = new Thread(() =>
{
// Continually get the next task and try to execute it.
// This will continue until the scheduler is disposed and no more tasks remain.
foreach (var t in _tasks.GetConsumingEnumerable())
{
TryExecuteTask(t);
}
});
thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.STA);
return thread;
}).ToList();
// Start all of the threads
_threads.ForEach(t => t.Start());
}
/// <summary>Queues a Task to be executed by this scheduler.</summary>
/// <param name="task">The task to be executed.</param>
protected override void QueueTask(Task task)
{
// Push it into the blocking collection of tasks
_tasks.Add(task);
}
/// <summary>Provides a list of the scheduled tasks for the debugger to consume.</summary>
/// <returns>An enumerable of all tasks currently scheduled.</returns>
protected override IEnumerable<Task> GetScheduledTasks()
{
// Serialize the contents of the blocking collection of tasks for the debugger
return _tasks.ToArray();
}
/// <summary>Determines whether a Task may be inlined.</summary>
/// <param name="task">The task to be executed.</param>
/// <param name="taskWasPreviouslyQueued">Whether the task was previously queued.</param>
/// <returns>true if the task was successfully inlined; otherwise, false.</returns>
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
// Try to inline if the current thread is STA
return
Thread.CurrentThread.GetApartmentState() == ApartmentState.STA &&
TryExecuteTask(task);
}
/// <summary>Gets the maximum concurrency level supported by this scheduler.</summary>
public override int MaximumConcurrencyLevel
{
get { return _threads.Count; }
}
/// <summary>
/// Cleans up the scheduler by indicating that no more tasks will be queued.
/// This method blocks until all threads successfully shutdown.
/// </summary>
public void Dispose()
{
if (_tasks != null)
{
// Indicate that no new tasks will be coming in
_tasks.CompleteAdding();
// Wait for all threads to finish processing tasks
foreach (var thread in _threads) thread.Join();
// Cleanup
_tasks.Dispose();
_tasks = null;
}
}
}
}
#2
To add to Vadim's limitation you can set the default printer before printing by using:
要添加到Vadim的限制,您可以使用以下方法在打印前设置默认打印机:
static void SetAsDefaultPrinter(string printerDevice)
{
foreach (var printer in PrinterSettings.InstalledPrinters)
{
//verify that the printer exists here
}
var path = "win32_printer.DeviceId='" + printerDevice + "'";
using (var printer = new ManagementObject(path))
{
printer.InvokeMethod("SetDefaultPrinter",
null, null);
}
return;
}
And changeing slightly the PrintHtml method with:
并稍微改变PrintHtml方法:
public void PrintHtml(string htmlPath, string printerDevice)
{
if (!string.IsNullOrEmpty(printerDevice))
SetAsDefaultPrinter(printerDevice);
Task.Factory.StartNew(() => PrintOnStaThread(htmlPath), CancellationToken.None, TaskCreationOptions.None, _sta).Wait();
}
Now I don't know how that will fair in a heavy printing environment considering there could be concurrency issues with changeing the default printer a lot. But so far this is the best I came up with to fix this limitation.
现在我不知道在重型打印环境中如何公平,考虑到可能存在更改默认打印机的并发问题。但到目前为止,这是我想出来解决这个限制的最好方法。
#3
In windows service the Microsoft web browser control is not working. I had used that code it's working fine in windows application but when i am using within a windows service then the program getting stuck in this line
在Windows服务中,Microsoft Web浏览器控件无法正常工作。我曾经使用过该代码,它在Windows应用程序中工作正常,但是当我在Windows服务中使用时,程序卡在这一行中
axWebBrowser1.Navigate(@"C:\mydoc.html", ref empty, ref empty, ref empty, ref empty);
axWebBrowser1.Navigate(@“C:\ mydoc.html”,ref为空,ref为空,ref为空,ref为空);
thanks for reply, Anup Pal
感谢回复,Anup Pal
#1
Here's the Holy Grail.
这是圣杯。
Taking advantage of StaTaskScheduler (taken from Parallel Extension Extras (release on Code Gallery)).
利用StaTaskScheduler(取自Parallel Extension Extras(在代码库中发布))。
Features: waits for the printing completion, doesn't show print settings, hopefully reliable.
特点:等待打印完成,不显示打印设置,希望可靠。
Limitations: requires C# 4.0, uses default printer, doesn't allow to change print template
限制:需要C#4.0,使用默认打印机,不允许更改打印模板
TaskScheduler Sta = new StaTaskScheduler(1);
public void PrintHtml(string htmlPath)
{
Task.Factory.StartNew(() => PrintOnStaThread(htmlPath), CancellationToken.None, TaskCreationOptions.None, Sta).Wait();
}
void PrintOnStaThread(string htmlPath)
{
const short PRINT_WAITFORCOMPLETION = 2;
const int OLECMDID_PRINT = 6;
const int OLECMDEXECOPT_DONTPROMPTUSER = 2;
using(var browser = new WebBrowser())
{
browser.Navigate(htmlPath);
while(browser.ReadyState != WebBrowserReadyState.Complete)
Application.DoEvents();
dynamic ie = browser.ActiveXInstance;
ie.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER, PRINT_WAITFORCOMPLETION);
}
}
//--------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: StaTaskScheduler.cs
//
//--------------------------------------------------------------------------
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace System.Threading.Tasks.Schedulers
{
/// <summary>Provides a scheduler that uses STA threads.</summary>
public sealed class StaTaskScheduler : TaskScheduler, IDisposable
{
/// <summary>Stores the queued tasks to be executed by our pool of STA threads.</summary>
private BlockingCollection<Task> _tasks;
/// <summary>The STA threads used by the scheduler.</summary>
private readonly List<Thread> _threads;
/// <summary>Initializes a new instance of the StaTaskScheduler class with the specified concurrency level.</summary>
/// <param name="numberOfThreads">The number of threads that should be created and used by this scheduler.</param>
public StaTaskScheduler(int numberOfThreads)
{
// Validate arguments
if (numberOfThreads < 1) throw new ArgumentOutOfRangeException("concurrencyLevel");
// Initialize the tasks collection
_tasks = new BlockingCollection<Task>();
// Create the threads to be used by this scheduler
_threads = Enumerable.Range(0, numberOfThreads).Select(i =>
{
var thread = new Thread(() =>
{
// Continually get the next task and try to execute it.
// This will continue until the scheduler is disposed and no more tasks remain.
foreach (var t in _tasks.GetConsumingEnumerable())
{
TryExecuteTask(t);
}
});
thread.IsBackground = true;
thread.SetApartmentState(ApartmentState.STA);
return thread;
}).ToList();
// Start all of the threads
_threads.ForEach(t => t.Start());
}
/// <summary>Queues a Task to be executed by this scheduler.</summary>
/// <param name="task">The task to be executed.</param>
protected override void QueueTask(Task task)
{
// Push it into the blocking collection of tasks
_tasks.Add(task);
}
/// <summary>Provides a list of the scheduled tasks for the debugger to consume.</summary>
/// <returns>An enumerable of all tasks currently scheduled.</returns>
protected override IEnumerable<Task> GetScheduledTasks()
{
// Serialize the contents of the blocking collection of tasks for the debugger
return _tasks.ToArray();
}
/// <summary>Determines whether a Task may be inlined.</summary>
/// <param name="task">The task to be executed.</param>
/// <param name="taskWasPreviouslyQueued">Whether the task was previously queued.</param>
/// <returns>true if the task was successfully inlined; otherwise, false.</returns>
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
// Try to inline if the current thread is STA
return
Thread.CurrentThread.GetApartmentState() == ApartmentState.STA &&
TryExecuteTask(task);
}
/// <summary>Gets the maximum concurrency level supported by this scheduler.</summary>
public override int MaximumConcurrencyLevel
{
get { return _threads.Count; }
}
/// <summary>
/// Cleans up the scheduler by indicating that no more tasks will be queued.
/// This method blocks until all threads successfully shutdown.
/// </summary>
public void Dispose()
{
if (_tasks != null)
{
// Indicate that no new tasks will be coming in
_tasks.CompleteAdding();
// Wait for all threads to finish processing tasks
foreach (var thread in _threads) thread.Join();
// Cleanup
_tasks.Dispose();
_tasks = null;
}
}
}
}
#2
To add to Vadim's limitation you can set the default printer before printing by using:
要添加到Vadim的限制,您可以使用以下方法在打印前设置默认打印机:
static void SetAsDefaultPrinter(string printerDevice)
{
foreach (var printer in PrinterSettings.InstalledPrinters)
{
//verify that the printer exists here
}
var path = "win32_printer.DeviceId='" + printerDevice + "'";
using (var printer = new ManagementObject(path))
{
printer.InvokeMethod("SetDefaultPrinter",
null, null);
}
return;
}
And changeing slightly the PrintHtml method with:
并稍微改变PrintHtml方法:
public void PrintHtml(string htmlPath, string printerDevice)
{
if (!string.IsNullOrEmpty(printerDevice))
SetAsDefaultPrinter(printerDevice);
Task.Factory.StartNew(() => PrintOnStaThread(htmlPath), CancellationToken.None, TaskCreationOptions.None, _sta).Wait();
}
Now I don't know how that will fair in a heavy printing environment considering there could be concurrency issues with changeing the default printer a lot. But so far this is the best I came up with to fix this limitation.
现在我不知道在重型打印环境中如何公平,考虑到可能存在更改默认打印机的并发问题。但到目前为止,这是我想出来解决这个限制的最好方法。
#3
In windows service the Microsoft web browser control is not working. I had used that code it's working fine in windows application but when i am using within a windows service then the program getting stuck in this line
在Windows服务中,Microsoft Web浏览器控件无法正常工作。我曾经使用过该代码,它在Windows应用程序中工作正常,但是当我在Windows服务中使用时,程序卡在这一行中
axWebBrowser1.Navigate(@"C:\mydoc.html", ref empty, ref empty, ref empty, ref empty);
axWebBrowser1.Navigate(@“C:\ mydoc.html”,ref为空,ref为空,ref为空,ref为空);
thanks for reply, Anup Pal
感谢回复,Anup Pal