Print html document from Windows Service in C# without print dialog

后端 未结 3 1372
生来不讨喜
生来不讨喜 2020-12-03 03:58

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

相关标签:
3条回答
  • 2020-12-03 04:32

    Here's the Holy Grail.

    Taking advantage of StaTaskScheduler (taken from Parallel Extension Extras (release on Code Gallery)).

    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

        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;
                }
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-03 04:36

    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

    axWebBrowser1.Navigate(@"C:\mydoc.html", ref empty, ref empty, ref empty, ref empty);

    thanks for reply, Anup Pal

    0 讨论(0)
  • 2020-12-03 04:46

    To add to Vadim's limitation you can set the default printer before printing by using:

        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:

        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.

    0 讨论(0)
提交回复
热议问题