I have a Delphi app which prints HTML to PDF by opening the document in IE11 in the background and using the default PDF printer to print to PDF. This process works fine.
The issue is the following:
(Example I want to print 5 HTML documents to PDF.)
On the first run, it processes the first document fine, but then skips the rest with the following errors:
On Win Server 2016:
EOleSysErrorOLE A system shutdown has already been scheduled.
On Windows 10:
EOleSysErrorOLE error 8150002E
Then I wait until "iexplore.exe" closes, which takes a few sec. From then, it processes all documents just fine regardless the number of the documents.
If I do not use the app for a long time (approx a day), it does the same as above.
It skips on the first run, then waits a few seconds and then us fine.
I tried to use OleVariant and IWebBrowser2, but both have the same outcome.
I close the Object with .Quit. (see in code below). I also tried Unassigned, Free, setting the Object to Null before creating a new object. None of them worked. Same outcome.
Here are a few thing which I tried as a workaround:
If I do not use
.Quit, it works fine, but obviously won't close any iexplore.exe.Also, if I open an IE window (GUI) and minimize it, the HTML-PDF process works fine.
I also tried to call to create a background IE object on
TMainForm.FormCreate()when the app starts, and it works as well. When it gets to the HTML-PDF process, it creates a new IE background object (additional "iexplore.exe") and closes it by leaving the one created onFormCreate().
I would like to figure out why it just cannot create and close an object fast enough on the first run (without having an IE opened or without using .Quit).
Here is the code:
Note: The program also writes some stuff to the registry, but I cut some lines for simplicity (I also might cut a few end here and there. Note that the function works fine apart than the issue above).
function THTMLMergeDocument.FilePrint: boolean;
var
BrowserObject: OleVariant;
ie : IWebBrowser2;
vaIn, vaOut: OleVariant;
OldHeader, OldFooter, OldPrinterName: String;
OldOrientation: Integer;
Registry : TRegistry;
ST, TOutVal: TDateTime;
sUrl : string;
Flag, TargetFrameName, PostData, Headers : OleVariant;
begin
result := false;
try
if fPrinterName = VTPrint.GetDefaultPrinter then
begin
try
//Tried OleVariant
{
BrowserObject := Unassigned;
BrowserObject := CreateOleObject('InternetExplorer.Application');
BrowserObject.Silent := true;
BrowserObject.Visible := false;
BrowserObject.Navigate('file:\\'+DocumentFileName);
BrowserObject.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER);
while BrowserObject.Busy or BrowserObject.ReadyState <> READYSTATE_COMPLETE do
begin
Application.ProcessMessages;
end;
}
//Tried IWebBrowser2
ie := CoInternetExplorer.Create;
sUrl := 'file:\\'+DocumentFileName;
ie.Navigate(sUrl, Flag, TargetFrameName, PostData, Headers);
ie.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER,vaIn,vaOut);
while ie.ReadyState <> READYSTATE_COMPLETE do
begin
Application.ProcessMessages;
end;
if (PDFOutput) then
begin
ST := Now;
TOutVal := EncodeTime(0,DocumentServerOptions.PDFConverterTimeOutInterval,0,0);
while not PDF.Completed and (Now-ST<TOutVal) do
Application.ProcessMessages;
if PDF.Completed then
result := true
else
WinWordLogProc('ERROR: No response received from PDF converter');
end
else
begin
result := true;
end;
ie.Quit; //close IWebBrowser2 object
BrowserObject.Quit; //close OleVariant object
except on E: Exception do
WinWordLogProc( 'Error class: ' + E.ClassName + #13 + E.Message);
end;
end
else
begin
WinWordLogProc('Error setting default printer to '+fPrinterName);
end;
finally
VTPrint.SetDefaultPrinter(OldPrinterName);
end;
`
I suspect that it has something do do with the IE object handling, but I'm not sure, hence asking for help here.
The browser's
Navigate()method is asynchronous. You should wait for the document to finish loading before you then callExecWB()to print the document, not after calling it.