当我把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,与君共勉。