Web打印在实际应用中比较广泛,比如公司报表、银行回单等。如果是直接在网页中嵌入打印比较简单,直接使用JS的打印功能。但如果生成的报表以html的形式存储于本地呢?下面基于vc++介绍两种方法。
大致流程如下:
这种方式有很大的缺点,可控性差,有时可能默认浏览器不是IE、或者浏览器注册表被修改都会导致创建IE COM组件失败。并且每次打印都要去创建一次COM组件,打印完成再释放浏览器。如果通过增加COM引用计数的方式,经测试加载文档会失败,可能没有更深入的了解,微软官网上也是看得一知半解。
使用CHtmlView有两种方式,建工程时可以选择文档\视图结构,也可以选择基于对话框模式。如果选择文档\视图模式,后续选择工程视图的基类为CHtmlView,这样编译器会自动添加消息映射。
使用这种方式相对简单,只需添加如下消息映射:
BEGIN_MESSAGE_MAP(CWebBrowserDocumentView, CHtmlView)
//{{AFX_MSG_MAP(CWebBrowserDocumentView)
ON_COMMAND(ID_FILE_PRINT, OnFilePrint)
ON_WM_DESTROY()
//}}AFX_MSG_MAP
// Standard printing commands
//ON_COMMAND(ID_FILE_PRINT, CHtmlView::OnFilePrint)
END_MESSAGE_MAP()
如果消息映射为 ON_COMMAND(ID_FILE_PRINT, CHtmlView::OnFilePrint),点击打印的时候会弹出打印设置对话框(CPrintDialog),为了屏蔽对话框,需自己实现打印,所以添加ON_COMMAND(ID_FILE_PRINT, OnFilePrint)消息映射,然后在类里面添加消息响应方法:afx_msg void OnFilePrint()。
那么要怎么实现OnFilePrint()方法呢?
在vc编译器的安装目录:“VC98\MFC\SRC”下有个VIEWHTML.cpp文件,打开可以看到打印的实现方法,如下:
void CHtmlView::OnFilePrint()
{
// get the HTMLDocument
if (m_pBrowserApp != NULL)
{
LPOLECOMMANDTARGET lpTarget = NULL;
LPDISPATCH lpDisp = GetHtmlDocument();
if (lpDisp != NULL)
{
// the control will handle all printing UI
if (SUCCEEDED(lpDisp->QueryInterface(IID_IOleCommandTarget,
(LPVOID*) &lpTarget)))
{
lpTarget->Exec(NULL, OLECMDID_PRINT, 0, NULL, NULL);
lpTarget->Release();
}
lpDisp->Release();
}
}
}
所以,直接拿过来用就可以了。下面看一下IOleCommandTarget接口的Exec方法:
HRESULT Exec(
[in] const GUID *pguidCmdGroup,
[in] DWORD nCmdID,
[in] DWORD nCmdexecopt,
[in] VARIANT *pvaIn,
[in, out] VARIANT *pvaOut
);
参数:
pguidCmdGroup【in】 唯一的指令集标志,为NULL表示标准指令集,这里可以是CGID_MSHTML
nCmdID 【in】 要执行的指令ID,必须在pguidCmdGroup指定的指令集中
nCmdexecopt 【in】 指定如何执行该指令。可能取值为OLECMDEXECOPT和OLECMDID_WINDOWSTATE_FLAG的枚举值
pvaIn 【in】指向包含输入参数的VARIANTARG结构体指针,可以为NULL
pvaOut 【in out】 输出参数VARIANTARG结构体指针,可以为NULL注意:关键是nCmdID、nCmdexecopt的值,打印的时候为了不弹出打印设置对话框,nCmdexecopt的值为OLECMDEXECOPT_DONTPROMPTUSER.
基于对话框方式实际上也是间接使用文档\视图结构。首先定义一个框架类,如下:
class CWebPrintFrame : public CFrameWnd
{
public:
CWebPrintFrame();
DECLARE_DYNCREATE(CWebPrintFrame)
public:
virtual ~CWebPrintFrame();
public:
void OnFilePrint(char* url);
CWebPrintView *m_pView;
LPCTSTR m_szUrl;
BOOL m_bLoaded;
// Generated message map functions
protected:
//{{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnClose();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
实现如下:
//////////////////////////////////////////////////////////////////////
// CWebPrintFrame
//////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNCREATE(CWebPrintFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CWebPrintFrame, CFrameWnd)
//{{AFX_MSG_MAP(CWebPrintFrame)
ON_WM_CREATE()
ON_WM_CLOSE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
CWebPrintFrame::CWebPrintFrame()
{
if (!Create(NULL,"PrintPreview",WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE,
CRect(200,0,1224,800)))
{
TRACE0("Failed to create View Window!");
}
}
CWebPrintFrame::~CWebPrintFrame()
{
}
int CWebPrintFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
{
return -1;
}
CCreateContext contex;
contex.m_pNewViewClass = RUNTIME_CLASS(CWebPrintView);
contex.m_pCurrentFrame = this;
contex.m_pCurrentDoc = NULL;
contex.m_pLastView = NULL;
m_pView = STATIC_DOWNCAST(CWebPrintView,CreateView(&contex));
m_bLoaded = FALSE;
if (m_pView != NULL)
{
m_pView->ShowWindow(SW_SHOW);
SetActiveView(m_pView);
//SetLandscapeMode(DMORIENT_PORTRAIT);
}
ShowWindow(SW_SHOW);
CWinApp *pApp = AfxGetApp();
pApp->m_pMainWnd = this;
return 0;
}
void CWebPrintFrame::OnFilePrint(char* url)
{
this->m_szUrl = url;
m_pView->Navigate2(m_szUrl,NULL,NULL);
//等待加载完成
MSG msg;
while(!m_bLoaded)
{
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
//直接打印
m_pView->SendMessage(WM_COMMAND,ID_FILE_PRINT);
}
void CWebPrintFrame::OnClose()
{
CWebPrintFrame *pFrame = (CWebPrintFrame *)::AfxGetMainWnd();
CWinApp *pApp = AfxGetApp();
//pApp->m_pMainWnd = pFrame->m_pDlg;
pFrame->DestroyWindow();
//CFrameWnd::OnClose();
}
然后定义视图类,如下:
class CWebPrintView : public CHtmlView
{
public:
CWebPrintView();
DECLARE_DYNCREATE(CWebPrintView)
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CWebPrintView)
public:
virtual void OnDraw(CDC* pDC); // overridden to draw this view
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual void OnInitialUpdate(); // called first time after construct
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CWebPrintView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
//{{AFX_MSG(CWebPrintView)
afx_msg void OnFilePrint();
afx_msg void OnDocumentComplete(LPCTSTR lpszURL);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
实现如下:
//////////////////////////////////////////////////////////////////////
// CWebPrintView
//////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNCREATE(CWebPrintView, CHtmlView)
BEGIN_MESSAGE_MAP(CWebPrintView, CHtmlView)
//{{AFX_MSG_MAP(CWebPrintView)
ON_COMMAND(ID_FILE_PRINT, OnFilePrint)
ON_COMMAND(READYSTATE_COMPLETE,OnDocumentComplete)
//}}AFX_MSG_MAP
// Standard printing commands
END_MESSAGE_MAP()
CWebPrintView::CWebPrintView()
{
}
CWebPrintView::~CWebPrintView()
{
}
BOOL CWebPrintView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CHtmlView::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// CWebPrintView drawing
void CWebPrintView::OnDraw(CDC* pDC)
{
ASSERT_VALID(pDC);
}
void CWebPrintView::OnInitialUpdate()
{
CHtmlView::OnInitialUpdate();
}
/////////////////////////////////////////////////////////////////////////////
// CWebPrintView diagnostics
#ifdef _DEBUG
void CWebPrintView::AssertValid() const
{
CHtmlView::AssertValid();
}
void CWebPrintView::Dump(CDumpContext& dc) const
{
CHtmlView::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CPrintView message handlers
void CWebPrintView::OnFilePrint()
{
LPOLECOMMANDTARGET lpTarget = NULL;
LPDISPATCH lpDisp = GetHtmlDocument();
if (lpDisp != NULL)
{
// the control will handle all printing UI
if (SUCCEEDED(lpDisp->QueryInterface(IID_IOleCommandTarget,
(LPVOID*) &lpTarget)))
{
lpTarget->Exec(NULL, OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
lpTarget->Release();
}
lpDisp->Release();
}
}
void CWebPrintView::OnDocumentComplete(LPCTSTR lpszURL)
{
CHtmlView::OnDocumentComplete(lpszURL);
CWebPrintFrame* pFrame= (CWebPrintFrame* )AfxGetMainWnd();
pFrame->m_bLoaded = TRUE;
}
调用方式如下:
CWebPrintFrame* pFrame = new CWebPrintFrame();
pFrame->OnFilePrint(szURL);