rdvojmoc / DinkToPdf

C# .NET Core wrapper for wkhtmltopdf library that uses Webkit engine to convert HTML pages to PDF.
MIT License
1.08k stars 415 forks source link

Qt: Could not initialize OLE (error 80010106) #119

Open mboukhlouf opened 4 years ago

mboukhlouf commented 4 years ago

I'm working on a ASP.NET Core MVC app and I wanted to use DinkToPdf library to convert Html to PDF. I get this error in the console, when I first access a page that uses the IConverter from the services:

Qt: Could not initialize OLE (error 80010106)

I still get the PDF with no issues. I think the issue is somewhere around calling: new SynchronizedConverter(new PdfTools()) As I have it in the services as a singleton and only called the first time it's accessed:

services.AddSingleton(typeof(IConverter), new SynchronizedConverter(new PdfTools()));
Cafnio commented 4 years ago

Have the same problem. It genereates the PDF, yet, the error is throw on the first call

PeterWone commented 3 years ago

The same error is reported by the BasicConverter under the same conditions.

leijae commented 3 years ago

Also getting this issue with OPs setting, I get this error with Haukcode.Wkhtmltopdf.netcore also... I think this is an issue with wkhtmltopdf.... but not sure. Can we get a point in the right direction? image

PeterWone commented 3 years ago

I've abandoned wkhtmltopdf in favour of Chrome based solutions. Similar concept but using the debugging protocol to control headless Chrome. The wrappers aren't as mature but the handling of CSS and things like SVG are so much better it's not funny.

leijae commented 3 years ago

That's awesome for you, but not sure how that helps when trying to generate thousands of pdfs as a background task in an azure function.

PeterWone commented 3 years ago

I've not written an Azure function but if you're using wkhtmltopdf that implies you can at least load a DLL.

An exe might not work directly in an Azure function but what stops you from using more appropriate hosting to implement HTML to PDF as a web service and using it that way? Generation time is a few hundred ms for single page documents.

If that's not good enough, Chromium is open source. Contribute a direct API and make yourself very popular.

WalissonPires commented 3 years ago

I am seeing the same message. But it is still generating the PDF. Using .NET 5

distantcam commented 3 years ago

I've just hit this problem too, in an Azure Isolated Functions host project.

I'm pretty sure this issue is due to the worker thread in SynchronizedConverter not being STA mode. So I copied the SynchronizedConverter and made an STA version.

public class STASynchronizedConverter : BasicConverter
{
    Thread conversionThread;

    BlockingCollection<Task> conversions = new BlockingCollection<Task>();

    bool kill = false;

    private readonly object startLock = new object();

    public STASynchronizedConverter(ITools tools) : base(tools)
    {
    }

    public override byte[] Convert(IDocument document)
    {
        return Invoke(() => base.Convert(document));
    }

    public TResult Invoke<TResult>(Func<TResult> @delegate)
    {
        StartThread();

        Task<TResult> task = new Task<TResult>(@delegate);

        lock (task)
        {
            //add task to blocking collection
            conversions.Add(task);

            //wait for task to be processed by conversion thread
            Monitor.Wait(task);
        }

        //throw exception that happened during conversion
        if (task.Exception != null)
        {
            throw task.Exception;
        }

        return task.Result;
    }

    private void StartThread()
    {
        lock (startLock)
        {
            if (conversionThread == null)
            {
                conversionThread = new Thread(Run)
                {
                    IsBackground = true,
                    Name = "wkhtmltopdf worker thread"
                };

                // This is to fix issue https://github.com/rdvojmoc/DinkToPdf/issues/119
                conversionThread.SetApartmentState(ApartmentState.STA);

                kill = false;

                conversionThread.Start();
            }
        }
    }

    private void StopThread()
    {
        lock (startLock)
        {
            if (conversionThread != null)
            {
                kill = true;

                while (conversionThread.ThreadState == ThreadState.Stopped)
                { }

                conversionThread = null;
            }
        }
    }

    private void Run()
    {
        while (!kill)
        {
            //get next conversion taks from blocking collection
            Task task = conversions.Take();

            lock (task)
            {
                //run taks on thread that called RunSynchronously method
                task.RunSynchronously();

                //notify caller thread that task is completed
                Monitor.Pulse(task);
            }
        }
    }
}
Cactusman07 commented 3 years ago

I also see this error. I can run this in an Azure function app once - it generates the PDF fine and throws this error, however subsequent calls to the function app fail (502 / 503 or just timeout / hang until I cancel the request)

jombard commented 2 years ago

I resolved the issue of failing to produce the second call to the Azure function by creating a startup class to handle the singleton

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using DinkToPdf;
using DinkToPdf.Contracts;

[assembly: FunctionsStartup(typeof(Html2Pdf.Startup))]

namespace Html2Pdf
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder) 
        {
            builder.Services.AddSingleton(typeof(IConverter), new SynchronizedConverter(new PdfTools()));
        }
    }
}

See here for more https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection

Workaholic01 commented 2 years ago

Hey,

I am using the library with .Net 5 console app. I am facing the same error

Qt: Could not initialize OLE (error 80010106)

This is my code:

` static void Main(string[] args) { var converter = new BasicConverter(new PdfTools());

        //converter.PhaseChanged += Converter_PhaseChanged;
        //converter.ProgressChanged += Converter_ProgressChanged;
        //converter.Finished += Converter_Finished;
        //converter.Warning += Converter_Warning;
        //converter.Error += Converter_Error;

        var doc = new HtmlToPdfDocument()
        {
            GlobalSettings = {
                ColorMode = ColorMode.Color,
                Orientation = Orientation.Landscape,
                PaperSize = PaperKind.A4,
            },
            Objects = {
                new ObjectSettings() {
                    PagesCount = true,
                    HtmlContent = @"Lorem ipsum dolor sit amet, consectetur adipiscing elit. In consectetur mauris eget ultrices iaculis. Ut et odio viverra, molestie lectus nec, venenatis turpis. Nulla quis euismod nisl. Duis scelerisque eros nec dui facilisis, sit amet porta odio varius. Praesent vitae sollicitudin leo. Sed vitae quam in massa eleifend porta. Aliquam pulvinar orci dapibus porta laoreet. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed commodo tortor eget dolor hendrerit dapibus.
                                    Vivamus lorem diam, vulputate at ultrices quis, tristique eu nunc. Sed bibendum hendrerit leo. Nulla nec risus turpis. Vivamus at tortor felis. Donec eget posuere libero. Pellentesque erat nunc, molestie eget gravida vitae, eleifend a eros. Integer in tortor sed elit aliquam vehicula eget a erat. Vivamus nisi augue, venenatis ut commodo vel, congue id neque. Curabitur convallis dictum semper. Nulla accumsan urna aliquet, mattis dolor molestie, fermentum metus. Quisque at nisi non augue tempor commodo et pretium orci.
                                    Quisque blandit libero ut laoreet venenatis. Morbi sit amet quam varius, euismod dui et, volutpat felis. Sed nec ante vel est convallis placerat. Morbi mollis pretium tempor. Aliquam luctus eu justo vitae tristique. Sed in elit et elit sagittis pharetra sed vitae velit. Proin eget mi facilisis, scelerisque justo in, ornare urna. Aenean auctor ante ex, eget mattis neque pretium id. Aliquam ut risus leo. Vivamus ullamcorper et mauris in vehicula. Maecenas tristique interdum tempus. Etiam mattis lorem eget odio faucibus, in rhoncus nisi ultrices. Etiam at convallis nibh. Suspendisse tincidunt velit arcu, a volutpat nulla euismod sed.
                                    Aliquam mollis placerat blandit. Morbi in nibh urna. Donec nisl enim, tristique id tincidunt sed, pharetra non mi. Morbi viverra arcu vulputate risus dignissim efficitur. Vivamus dolor eros, finibus et porttitor a, pellentesque a lectus. Integer pellentesque maximus velit sit amet sollicitudin. Nulla a elit eget augue pretium luctus quis eu metus. Aenean nec dui id nibh tempor dapibus. Pellentesque dignissim ullamcorper mauris, vitae pharetra turpis sodales sit amet. Etiam et bibendum neque.
                                    Nulla gravida sit amet velit eu aliquet. Etiam sit amet elit leo. Sed nec arcu tincidunt, placerat turpis quis, laoreet nulla. Aenean neque est, fringilla non nulla in, laoreet vehicula nunc. Etiam vel nisl sit amet lectus pellentesque eleifend. Etiam sed nisi dolor. Mauris quis tincidunt ex. Aliquam porta mattis tempor. Maecenas fringilla bibendum elementum. Vestibulum quis tempus libero, vitae cursus neque. Suspendisse lectus risus, lacinia consectetur enim quis, ullamcorper porta tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
                    WebSettings = { DefaultEncoding = "utf-8" },
                    HeaderSettings = { FontSize = 9, Right = "Page [page] of [toPage]", Line = true },
                    FooterSettings = { FontSize = 9, Right = "Page [page] of [toPage]" }
                }
            }
        };

        byte[] pdf = converter.Convert(doc);

        if (!Directory.Exists("Files"))
        {
            Directory.CreateDirectory("Files");
        }

        using (FileStream stream = new FileStream(@"Files\" + DateTime.UtcNow.Ticks.ToString() + ".pdf", FileMode.Create))
        {
            stream.Write(pdf, 0, pdf.Length);
        }

        Console.ReadKey();
        Console.WriteLine("Hello World!");
    }`

Any resolution so far?

ghost commented 2 years ago

@distantcam provided the solution. It works fine @Workaholic01. Those who may be checking this page in search of a solution, implement the solution by @distantcam. works for dotnet 6 .. @distantcam Thanks for the solution

krasnyd commented 2 years ago

@distantcam solution works fine on Windows, but the function SetApartmentState is not available on Linux. Is there something that works on both platforms?

zanyar3 commented 1 year ago

Thanks, @distantcam it is work.

only notice for all, To access the Converter class, you must inject it, not create a new instance.

public YourService(IIConverter converter) 
{
        _converter = converter;
}
swotiendang commented 5 months ago

@distantcam works like a charm

dqmarkmagaoay commented 2 months ago

how come for all these years the fix given by @distantcam still does not apply to the SynchronizedConverter class? is this library not being maintained anymore?

swotiendang commented 2 months ago

HI @dqmarkmagaoay , this library is no longer maintained, from my stressed test output, it can serve around 1.5K request/per hour. If it won't fit your need, you need to use PDFSharp, or headless pdf, or a paid library.

dqmarkmagaoay commented 2 months ago

HI @dqmarkmagaoay , this library is no longer maintained, from my stressed test output, it can serve around 1.5K request/per hour. If it won't fit your need, you need to use PDFSharp, or headless pdf, or a paid library.

Thanks for the info and reply @swotiendang , i was just curious as to why fixes are not being applied. This still fits my needs and may continue to use it at the moment.

balajiv27 commented 2 months ago

thanks much @distantcam running it in Azure function smoothly now

dqmarkmagaoay commented 2 months ago

thanks much @distantcam running it in Azure function smoothly now

@balajiv27 i just wanna ask, have you tried it as an Azure App?