问题
I am using the following unit to display - and print - HTML code via a TWebBrowser which is displayed in a non-modal dialog. In my production program, the following code works under Windows-XP but fails with Windows-7 (the error message is always External exception C015D00F). In order to isolate the problem, I wrote a simple test program which also has a non-modal dialog containing a TWebBrowser; on its own, this test program works correctly with Windows-7, but when I plug the non-modal dialog from the test program into the production program, I get the external exception.
This presumably indicates that there is a problem with the calling program and not the called unit, but I can't see what that problem is. The HTML code is hand crafted but displays correctly.
What could be the problem? The printing code comes from the Embarcadero site
unit Test4;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, OleCtrls, SHDocVw, MSHTML;
type
THTMLPreview = class(TForm)
web: TWebBrowser;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure webDocumentComplete(Sender: TObject; const pDisp: IDispatch;
var URL: OleVariant);
private
options: word;
fn: string;
procedure DoPrint;
public
Constructor Create (const afn, acapt: string; opts: word);
end;
implementation
{$R *.dfm}
constructor THTMLPreview.Create (const afn, acapt: string; opts: word);
begin
inherited create (nil);
caption:= acapt;
fn:= afn;
options:= opts;
web.Navigate (fn);
end;
procedure THTMLPreview.webDocumentComplete(Sender: TObject;
const pDisp: IDispatch; var URL: OleVariant);
begin
DoPrint
end;
procedure THTMLPreview.DoPrint;
var
HTMLDoc: IHTMLDocument2;
HTMLWnd: IHTMLWindow2;
HTMLWindow3: IHTMLWindow3;
begin
if options and 4 = 4 then
begin
HTMLDoc:= web.Document as IHTMLDocument2;
if HTMLDoc <> nil then
begin
HTMLWnd:= HTMLDoc.parentWindow;
HTMLWindow3:= HTMLWnd as IHTMLWindow3;
HTMLWindow3.print;
end
end
end;
procedure THTMLPreview.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if options and 1 = 1 then deletefile (fn);
action:= caFree
end;
end.
Using the statement Web.ControlInterface.ExecWB (OLECMDID_PRINT, OLECMDEXECOPT_PROMPTUSER,
vaIn, vaOut)
gives the same error.
Edit from a few days later:
I tried a completely different approach to the problem. In the HTML code I added a javascript snippet which displays a 'print' button and adds an 'onprint' event. Once again, this works fine on my development machine (XP) but not on my client's machines (Win7), where the program freezes with the announcement External exception C015D00F (same address as previously).
After no small amount of googling, I discovered that Exception code C015000F is caused by "the activation context being deactivated is not the most recently activated one." What does this mean to a poor Delphi programmer?
回答1:
If I remember correctly, the IHTMLWindow3.print method pops up the default 'sent to printer' system dialog. Do you want this? For an application I once searched for a way to avoid this, and then found this code.
var
r:TRect;
sh,ph:HDC;
begin
OleInitialize(nil);
WebBrowser1.Navigate('file://'+HtmlFilePath);
while WebBrowser1.ReadyState<>READYSTATE_COMPLETE do Application.HandleMessage;
//Printer.PrinterIndex:=//set selected printer here
Printer.BeginDoc;
try
Printer.Canvas.Lock;
try
sh:=GetDC(0);
ph:=Printer.Canvas.Handle;
//TODO: make rect a bit smaller for a page margin
//TODO: get page size from printer settings, assume A4 here (210x297mm)
r.Left:=0;
r.Top:=0;
r.Right:=2100 * GetDeviceCaps(sh,LOGPIXELSX) div 254;
r.Bottom:=2970 * GetDeviceCaps(sh,LOGPIXELSY) div 254;
WebBrowser1.BoundsRect:=r;
SetMapMode(ph,MM_ISOTROPIC);
SetWindowExtEx(ph,r.Right,r.Bottom,nil);
SetViewportExtEx(ph,r.Right,r.Bottom,nil);
r.Right:=GetDeviceCaps(ph,HORZRES)-1;
r.Bottom:=GetDeviceCaps(ph,VERTRES)-1;
(WebBrowser1.ControlInterface as IViewObject).Draw(
DVASPECT_CONTENT,
1,
nil,nil,0,ph,@r,nil,nil,0);
finally
Printer.Canvas.Unlock;
end;
Printer.EndDoc;
except
Printer.Abort;
raise;
end;
The SetWindowExtEx and SetViewportExtEx set the scaling correct so you can use the unit "mm" in the HTML/CSS.
回答2:
Try this.
var
vIn, vOut: OleVariant;
begin
WebBrowser_mail.ControlInterface.ExecWB(OLECMDID_PRINT,
OLECMDEXECOPT_PROMPTUSER, vIn, vOut) ;
回答3:
Whenever I have problems with WB it has two reasons: a) document is not fully loaded b) WB component is not "fully registered" because it is on hidden form etc.
For a) I use a lot of year this code:
var
CurDispatch: IDispatch;
DocLoaded: boolean;
procedure TForm3.WebBrowser1DocumentComplete(ASender: TObject;
const pDisp: IDispatch; const URL: OleVariant);
begin
if (pDisp = CurDispatch) then begin
CurDispatch := nil; {clear the global variable }
DocLoaded:=true;
end;
end;
procedure TForm3.WebBrowser1NavigateComplete2(ASender: TObject;
const pDisp: IDispatch; const URL: OleVariant);
begin
if CurDispatch = nil then
CurDispatch := pDisp; { save for comparison }
end;
procedure TForm3.Button1Click(Sender: TObject);
var
vIn, vOut: OleVariant;
begin
DocLoaded:=false;
WebBrowser1.Navigate(EdLink.Text);
repeat
Application.ProcessMessages;
until DocLoaded;
WebBrowser1.ControlInterface.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_PROMPTUSER, vIn, vOut)
end;
If still problems exist, try to put this to FormShow - it solves b):
WebBrowser1.HandleNeeded;
No problems with WB anymore.
Do not forget to set WebBrowser1.Silent:=true to hide JavaScript errors in page.
来源:https://stackoverflow.com/questions/15702976/printing-from-twebbrowser