您的位置:首页 > 其它

VC Web打印解决方案概述

2016-01-08 13:17 405 查看

VC Web打印解决方案概述

Web打印在实际应用中比较广泛,比如公司报表、银行回单等。如果是直接在网页中嵌入打印比较简单,直接使用JS的打印功能。但如果生成的报表以html的形式存储于本地呢?下面基于vc++介绍两种方法。

通过COM组建调用IE浏览器的打印功能

大致流程如下:

Created with Raphaël 2.1.0start//定义变量 IOleCommandTarget *pCommandTarget; IDispatch *pDispatch; IWebBrowser2 *pWebBrowser2; IUnknown *pUnknown;初始化COM:CoInitialize(NULL)调用CoCreateInstance(/****/)创建浏览器对象,并获取IUnknown接口指针调用IUnknown的方法QueryInterface()获取IWebBrowser2接口调用IWebBrowser2的Navigate方法导航到指定URL调用IWebBrowser2的get_Document()方法加载文档,输出IDispatch接口调用IDispatch的QueryInterface()方法获取IOleCommandTarget接口调用IOleCommandTarget的Exec()方法执行打印detect print statu print over?释放COM资源,然后调用CoUninitialize();Endyesno

这种方式有很大的缺点,可控性差,有时可能默认浏览器不是IE、或者浏览器注册表被修改都会导致创建IE COM组件失败。并且每次打印都要去创建一次COM组件,打印完成再释放浏览器。如果通过增加COM引用计数的方式,经测试加载文档会失败,可能没有更深入的了解,微软官网上也是看得一知半解。

使用MFC的CHtmlView的打印功能

使用CHtmlView有两种方式,建工程时可以选择文档\视图结构,也可以选择基于对话框模式。如果选择文档\视图模式,后续选择工程视图的基类为CHtmlView,这样编译器会自动添加消息映射。

.1 使用文档/视图方式

使用这种方式相对简单,只需添加如下消息映射:

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】 指定如何执行该指令。可能取值为OLECMDEXECOPTOLECMDID_WINDOWSTATE_FLAG的枚举值

pvaIn 【in】指向包含输入参数的VARIANTARG结构体指针,可以为NULL

pvaOut 【in out】 输出参数VARIANTARG结构体指针,可以为NULL

注意:关键是nCmdID、nCmdexecopt的值,打印的时候为了不弹出打印设置对话框,nCmdexecopt的值为OLECMDEXECOPT_DONTPROMPTUSER.

.2 基于对话框模式

基于对话框方式实际上也是间接使用文档\视图结构。首先定义一个框架类,如下:

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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: