CWebBrowser2加载打印心得

本文介绍了在MFC中使用CWebBrowser2控件进行网页加载和打印时遇到的问题及解决方案。作者发现Navigate函数是异步的,导致在加载未完成时调用ExecWB进行打印会报错。通过GetReadyState检查网页加载状态,并采用子线程配合自定义消息的方式,解决了跨线程调用COM函数的内存访问错误,实现了等待加载完成后再执行打印的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近学习在VC6下使用CWebBrowser2,目的是打印指定路径的网页。遇到了奇怪的问题。

当我把Navigate函数和ExecWB函数放在一起,程序运行报错,弹出一个没有内容的消息框。


当我把ExecWB函数放在另外的按钮上(例如"打印按钮"),程序执行正常。


猜测可能是网页加载状态问题,于是在网上真的找到了这个函数GetReadyState()

typedef enum tagREADYSTATE {
    READYSTATE_UNINITIALIZED = 0,
    READYSTATE_LOADING = 1,
    READYSTATE_LOADED = 2,
    READYSTATE_INTERACTIVE = 3,
    READYSTATE_COMPLETE = 4
} READYSTATE;


READYSTATE_UNINITIALIZED
Default initialization state.
READYSTATE_LOADING
Object is currently loading its properties.
READYSTATE_LOADED
Object has been initialized.
READYSTATE_INTERACTIVE
Object is interactive, but not all of its data is available.
READYSTATE_COMPLETE
Object has received all of its data.

所以必须等到GetReadyState()返回值是READYSTATE_COMPLETE时,网页才加载完成。当然加载完成了才能干后面的事情呀。


于是写了下面的代码

class CDlgWebPrint : public CDialog
{
// Construction
public:
    //…………
    CDlgWebPrint(CWnd* pParent = NULL);   // standard constructor
// Dialog Data
    //{{AFX_DATA(CDlgWebPrint)
    enum { IDD = IDD_DIALOG_WEBPRINT };
    CWebBrowser2    m_pWebPrint;
    //}}AFX_DATA
}
 
BOOL CDlgWebPrint::OnInitDialog() 
{
    CDialog::OnInitDialog();
     
    // TODO: Add extra initialization here
 
 
    this->m_pWebPrint.Navigate(_T("E:/temp.htm");, NULL, NULL, NULL, NULL);//打开strURL文件
//打印  
//  this->m_pWebPrint.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
    LONG n = 0;
    while (TRUE)
    {
        if (this->m_pWebPrint.GetReadyState() == READYSTATE_COMPLETE )
//READYSTATE_COMPLETE = 4,表示网页加载完成。但这里一直是READYSTATE_LOADING = 1,
//等了十几分钟还是1.我确定打开这个网页不需要1秒钟。还有什么玄机吗?吗吗吗?
        {
            this->m_pWebPrint.ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
            break;
        }
        else
        {
            if (n++ > 20)
            {
                AfxMessageBox(_T("加载网页失败"));
                return FALSE;
            }
 
            Sleep(500);
        }
    }  
     
    return TRUE;  // return TRUE unless you set the focus to a control
                  // EXCEPTION: OCX Property Pages should return FALSE
}


于是在论坛发了个帖子(http://bbs.youkuaiyun.com/topics/390392474?page=1#post-393918625)。幸好得到了oldmanzhao、fishion的指点。

为什么一直等待,但是加载没完成呢?原来CWebBrowser2::Navigate是个异步函数。因为异步函数,所以调用Navigate函数且得到返回值后,网页并没有加载好。当主程序Sleep时,主线程被挂起,线程“睡觉”了,导致CWebBrowser2::Navigate这个异步函数也“睡觉”,所以Sleep时,加载工作也停了。所以,等到猴年八月也等不到加载完成。

知道原因了,那问题应该简单了。第一步:调用Navigate加载URL,第二步:用某种方式监测加载状态GetReadyState,第三步:加载完成后调用ExecWB打印。1、3步很简单。对于异步,第二步有2种方法:计时器、子线程。计时器就是OnTime。我使用了子线程的方法达到目标。


子线程方法会遇到一个问题,子线程中不能调用ExecWB函数,会报内存访问错误。网上查来,是跨线程调用COM函数导致的。

于是我使用自定义消息,通过子线程发送消息,由主线程调用ExecWB函数。问题解决。但是在子线程中发送消息时,必须使用POSTMESSAGE,不可用SENDMESSAGE。猜测原因该是SENDMESSAGE发送时,还属于子线程调用吧(个人猜测)。


屌丝解决BUG,与君共勉。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值