==================================声明==================================
本文版权归作者所有
未经作者授权 请勿转载 保留法律追究的权利
本文原创,已获得转载授权的,必须在正文中显要地注明作者和出处,并保证文章(包括本声明)的完整性。
被授权人不可再次授权第三方。
未经作者授权请勿修改(包括本声明),保留法律追究的权利。
未经作者授权请勿用于学术性引用。
未经作者授权请勿用于商业出版、商业印刷、商业引用以及其他商业用途。 <--------总有一天我要自己做一个模板干掉这只土豆
本文不定期修正完善,为保证内容正确,建议移步原文处阅读。
本文链接:http://www.cnblogs.com/wlsandwho/p/4512840.html
=======================================================================
并没有找到什么好的资料
微软的官方文档里有一个SDI嵌入Excel的例子,再加上MFC的代码都是可见的,所以应该是可以搞一搞的。
这是微软官方文档https://support.microsoft.com/zh-cn/kb/184663网上对这篇古老的文章大肆抄袭。
我就不贴出来了,我这里用Win7 64+VC2010+Office 2007实现一下。
=======================================================================
万一哪天我忘了怎么弄这个,还能找找自己的博客,顺便感叹下自己曾经也是的。
=======================================================================
1 创建工程
下面的很重要,一定要选择为容器
2 添加Excel
这里我是64位系统,文件路径带x86,32位的不带这个。
点击完成和确定,MFC会自动生成一大堆类。(叫包装类更合适吧?)
这里要修改一下生成的.h文件。
CApplication.h文件是一定会用到的。注销到原来的第一行,添加三个import和三个using,不要问为什么,这里不是重点讲Office二次开发。
1 //#import "C:\\Program Files (x86)\\Microsoft Office\\Office12\\EXCEL.EXE" no_namespace 2 // CApplication 包装类 3 #import "C:\\Program Files (x86)\\Common Files\\microsoft shared\\OFFICE12\\MSO.DLL" rename("RGB","MSORGB") rename("DocumentProperties","MSODocumentProperties") 4 using namespace Office; 5 #import "C:\\Program Files (x86)\\Common Files\\microsoft shared\\VBA\\VBA6\\VBE6EXT.OLB" 6 using namespace VBIDE; 7 #import "C:\\Program Files (x86)\\Microsoft Office\\Office12\\EXCEL.EXE" rename("DialogBox","ExcelDialogBox") rename("RGB","ExcelRGB") rename("CopyFile","ExcelCopyFile") rename("ReplaceText","ExcelReplaceText") no_auto_exclude 8 using namespace Excel;
其他的.h文件,也是屏蔽原来的import,例如下面要用到
1 #include "CWorkbooks.h" 2 #include "CWorkbook.h" 3 #include "CWorksheets.h" 4 #include "CWorksheet.h" 5 #include "CRange.h"
我就把它们原来的第一个import都屏蔽了。
对于 “DialogBoxW”宏的实参不足
修改为
1 VARIANT _DialogBox()
3 修改CntrItem.h和CntrItem.cpp
由于之前添加了Excel,所以现在文件比较多,要慢慢找找。一定能找到的。
值得注意的是,这个文件名并没有遵循“文件名<=>类名”的国际惯例,例如我的这个Embed_ExcelWLS工程,文件名还是叫CntrItem.h,但是类名叫CEmbed_ExcelWLSCntrItem。
给CEmbed_ExcelWLSCntrItem类添加一个函数用于获得接口。(为了区别原有代码,我会在自己添加的代码前加一行“/”)
1 // CntrItem.h : CEmbed_ExcelWLSCntrItem 类的接口 2 // 3 4 #pragma once 5 6 class CEmbed_ExcelWLSDoc; 7 class CEmbed_ExcelWLSView; 8 9 class CEmbed_ExcelWLSCntrItem : public COleClientItem 10 { 11 DECLARE_SERIAL(CEmbed_ExcelWLSCntrItem) 12 13 // 构造函数 14 public: 15 CEmbed_ExcelWLSCntrItem(CEmbed_ExcelWLSDoc* pContainer = NULL); 16 // 注意: 允许 pContainer 为 NULL 以启用 IMPLEMENT_SERIALIZE 17 // IMPLEMENT_SERIALIZE 要求类具有带零 18 // 参数的构造函数。OLE 项通常是用 19 // 非 NULL 文档指针构造的 20 21 // 特性 22 public: 23 CEmbed_ExcelWLSDoc* GetDocument() 24 { return reinterpret_cast<CEmbed_ExcelWLSDoc*>(COleClientItem::GetDocument()); } 25 CEmbed_ExcelWLSView* GetActiveView() 26 { return reinterpret_cast<CEmbed_ExcelWLSView*>(COleClientItem::GetActiveView()); } 27 28 public: 29 virtual void OnChange(OLE_NOTIFICATION wNotification, DWORD dwParam); 30 virtual void OnActivate(); 31 32 protected: 33 virtual void OnGetItemPosition(CRect& rPosition); 34 virtual void OnDeactivateUI(BOOL bUndoable); 35 virtual BOOL OnChangeItemPosition(const CRect& rectPos); 36 virtual BOOL OnShowControlBars(CFrameWnd* pFrameWnd, BOOL bShow); 37 38 // 实现 39 public: 40 ~CEmbed_ExcelWLSCntrItem(); 41 #ifdef _DEBUG 42 virtual void AssertValid() const; 43 virtual void Dump(CDumpContext& dc) const; 44 #endif 45 virtual void Serialize(CArchive& ar); 46 47 ////////////////////////////////////////////////////////////////////////// 48 public: 49 LPDISPATCH GetIDispatch(); 50 };
1 ////////////////////////////////////////////////////////////////////////// 2 /******************************************************************* 3 * This method returns the IDispatch* for the application linked to 4 * this container. 5 ********************************************************************/ 6 LPDISPATCH CEmbed_ExcelWLSCntrItem::GetIDispatch() 7 { 8 //The this and m_lpObject pointers must be valid for this function 9 //to work correctly. The m_lpObject is the IUnknown pointer to 10 // this object. 11 ASSERT_VALID(this); 12 13 ASSERT(m_lpObject != NULL); 14 15 LPUNKNOWN lpUnk = m_lpObject; 16 17 //The embedded application must be running in order for the rest 18 //of the function to work. 19 Run(); 20 21 //QI for the IOleLink interface of m_lpObject. 22 LPOLELINK lpOleLink = NULL; 23 if (m_lpObject->QueryInterface(IID_IOleLink, 24 (LPVOID FAR*)&lpOleLink) == NOERROR) 25 { 26 ASSERT(lpOleLink != NULL); 27 lpUnk = NULL; 28 29 //Retrieve the IUnknown interface to the linked application. 30 if (lpOleLink->GetBoundSource(&lpUnk) != NOERROR) 31 { 32 TRACE0("Warning: Link is not connected!\n"); 33 lpOleLink->Release(); 34 return NULL; 35 } 36 ASSERT(lpUnk != NULL); 37 } 38 39 //QI for the IDispatch interface of the linked application. 40 LPDISPATCH lpDispatch = NULL; 41 if (lpUnk->QueryInterface(IID_IDispatch, (LPVOID FAR*)&lpDispatch) 42 !=NOERROR) 43 { 44 TRACE0("Warning: does not support IDispatch!\n"); 45 return NULL; 46 } 47 48 //After assuring ourselves it is valid, return the IDispatch 49 //interface to the caller. 50 ASSERT(lpDispatch != NULL); 51 return lpDispatch; 52 }
4 修改View文件
添加一个函数EmbedAutomateExcel
1 // Embed_ExcelWLSView.h : CEmbed_ExcelWLSView 类的接口 2 // 3 4 #pragma once 5 6 class CEmbed_ExcelWLSCntrItem; 7 8 class CEmbed_ExcelWLSView : public CView 9 { 10 protected: // 仅从序列化创建 11 CEmbed_ExcelWLSView(); 12 DECLARE_DYNCREATE(CEmbed_ExcelWLSView) 13 14 // 特性 15 public: 16 CEmbed_ExcelWLSDoc* GetDocument() const; 17 // m_pSelection 将所选内容保存在当前的 CEmbed_ExcelWLSCntrItem 中。 18 // 对于许多应用程序,这种成员变量不足以 19 // 表示某个选择,例如在不属于 CEmbed_ExcelWLSCntrItem 的对象中 20 // 选定的一个或多个对象。提供这种选择 21 // 机制的目的只是帮助您入门 22 23 // TODO: 用适合应用程序的选择机制替换此选择机制 24 CEmbed_ExcelWLSCntrItem* m_pSelection; 25 26 // 操作 27 public: 28 29 // 重写 30 public: 31 virtual void OnDraw(CDC* pDC); // 重写以绘制该视图 32 virtual BOOL PreCreateWindow(CREATESTRUCT& cs); 33 protected: 34 virtual void OnInitialUpdate(); // 构造后第一次调用 35 virtual BOOL OnPreparePrinting(CPrintInfo* pInfo); 36 virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo); 37 virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo); 38 virtual BOOL IsSelected(const CObject* pDocItem) const;// 容器支持 39 40 // 实现 41 public: 42 virtual ~CEmbed_ExcelWLSView(); 43 #ifdef _DEBUG 44 virtual void AssertValid() const; 45 virtual void Dump(CDumpContext& dc) const; 46 #endif 47 48 protected: 49 50 // 生成的消息映射函数 51 protected: 52 afx_msg void OnDestroy(); 53 afx_msg void OnSetFocus(CWnd* pOldWnd); 54 afx_msg void OnSize(UINT nType, int cx, int cy); 55 afx_msg void OnInsertObject(); 56 afx_msg void OnCancelEditCntr(); 57 afx_msg void OnFilePrint(); 58 afx_msg void OnFilePrintPreview(); 59 afx_msg void OnRButtonUp(UINT nFlags, CPoint point); 60 afx_msg void OnContextMenu(CWnd* pWnd, CPoint point); 61 DECLARE_MESSAGE_MAP() 62 63 ////////////////////////////////////////////////////////////////////////// 64 public: 65 void EmbedAutomateExcel(); 66 }; 67 68 #ifndef _DEBUG // Embed_ExcelWLSView.cpp 中的调试版本 69 inline CEmbed_ExcelWLSDoc* CEmbed_ExcelWLSView::GetDocument() const 70 { return reinterpret_cast<CEmbed_ExcelWLSDoc*>(m_pDocument); } 71 #endif
实现代码稍微改了下,毕竟office12不是excel9了。
1 ////////////////////////////////////////////////////////////////////////// 2 /******************************************************************** 3 * This method encapsulates the process of embedding an Excel 4 * Worksheet in a View object and automating that worksheet to add 5 * some text to cell A1. 6 ********************************************************************/ 7 void CEmbed_ExcelWLSView::EmbedAutomateExcel() 8 { 9 //Change the cursor so the user knows something exciting is going 10 //on. 11 BeginWaitCursor(); 12 13 CEmbed_ExcelWLSCntrItem* pItem = NULL; 14 TRY 15 { 16 //Get the document associated with this view, and be sure it's 17 //valid. 18 CEmbed_ExcelWLSDoc* pDoc = GetDocument(); 19 ASSERT_VALID(pDoc); 20 21 //Create a new item associated with this document, and be sure 22 //it's valid. 23 pItem = new CEmbed_ExcelWLSCntrItem(pDoc); 24 ASSERT_VALID(pItem); 25 26 // Get Class ID for Excel sheet. 27 // This is used in creation. 28 CLSID clsid; 29 if(FAILED(::CLSIDFromProgID(L"Excel.sheet",&clsid))) 30 //Any exception will do. We just need to break out of the 31 //TRY statement. 32 AfxThrowMemoryException(); 33 34 // Create the Excel embedded item. 35 if(!pItem->CreateNewItem(clsid)) 36 //Any exception will do. We just need to break out of the 37 //TRY statement. 38 AfxThrowMemoryException(); 39 40 //Make sure the new CContainerItem is valid. 41 ASSERT_VALID(pItem); 42 43 // Launch the server to edit the item. 44 pItem->DoVerb(OLEIVERB_SHOW, this); 45 46 // As an arbitrary user interface design, this sets the 47 // selection to the last item inserted. 48 m_pSelection = pItem; // set selection to last inserted item 49 pDoc->UpdateAllViews(NULL); 50 51 //Query for the dispatch pointer for the embedded object. In 52 //this case, this is the Excel worksheet. 53 LPDISPATCH lpDisp; 54 lpDisp = pItem->GetIDispatch(); 55 56 //Add text in cell A1 of the embedded Excel sheet 57 CApplication ExcelApp; 58 CWorkbooks ExcelBooks; 59 CWorkbook ExcelBook; 60 CWorksheets ExcelSheets; 61 CWorksheet ExcelSheet; 62 CRange ExcelRange; 63 64 65 ExcelBook.AttachDispatch(lpDisp); 66 ExcelApp=ExcelBook.get_Application(); 67 ExcelSheets=ExcelBook.get_Sheets(); 68 ExcelSheet=ExcelSheets.get_Item(COleVariant((short)1)); 69 ExcelRange=ExcelSheet.get_Range(COleVariant(TEXT("A1")),COleVariant(TEXT("A1"))); 70 ExcelRange.put_Item(_variant_t((long)1),_variant_t((long)1),_variant_t(TEXT("Hello Embed-Excel by WLS"))); 71 72 ExcelRange.ReleaseDispatch(); 73 ExcelSheet.ReleaseDispatch(); 74 ExcelSheets.ReleaseDispatch(); 75 ExcelBook.ReleaseDispatch(); 76 ExcelApp.Quit(); 77 ExcelApp.ReleaseDispatch(); 78 79 80 //NOTE: If you are automating Excel 2002, the Range.SetValue method has an 81 //additional optional parameter specifying the data type. Because the 82 //parameter is optional, existing code will still work correctly, but new 83 //code should use the new convention. The call for Excel2002 should look 84 //like the following: 85 86 //range.SetValue( ColeVariant( (long)DISP_E_PARAMNOTFOUND, VT_ERROR ), 87 // COleVariant("Hello, World!")); 88 } 89 90 //Here, we need to do clean up if something went wrong. 91 CATCH(CException, e) 92 { 93 if (pItem != NULL) 94 { 95 ASSERT_VALID(pItem); 96 pItem->Delete(); 97 } 98 AfxMessageBox(IDP_FAILED_TO_CREATE); 99 } 100 END_CATCH 101 102 //Set the cursor back to normal so the user knows exciting stuff 103 //is no longer happening. 104 EndWaitCursor(); 105 }
记得添加.h文件
5 修改OnInsertObject函数
1 void CEmbed_ExcelWLSView::OnInsertObject() 2 { 3 // 调用标准的“插入对象”对话框以获得有关 4 // 新 CEmbed_ExcelWLSCntrItem 对象的信息 5 // COleInsertDialog dlg; 6 // if (dlg.DoModal() != IDOK) 7 // return; 8 // 9 // BeginWaitCursor(); 10 // 11 // CEmbed_ExcelWLSCntrItem* pItem = NULL; 12 // TRY 13 // { 14 // // 创建与此文档相连接的新项 15 // CEmbed_ExcelWLSDoc* pDoc = GetDocument(); 16 // ASSERT_VALID(pDoc); 17 // pItem = new CEmbed_ExcelWLSCntrItem(pDoc); 18 // ASSERT_VALID(pItem); 19 // 20 // // 通过对话框数据初始化该项 21 // if (!dlg.CreateItem(pItem)) 22 // AfxThrowMemoryException(); // 任何异常都将导致该结果 23 // ASSERT_VALID(pItem); 24 // 25 // if (dlg.GetSelectionType() == COleInsertDialog::createNewItem) 26 // pItem->DoVerb(OLEIVERB_SHOW, this); 27 // 28 // ASSERT_VALID(pItem); 29 // // 作为任意用户界面设计,这会将所选内容 30 // // 设置为插入的最后一项 31 // 32 // // TODO: 重新实现所选内容,使其适合于您的应用程序 33 // m_pSelection = pItem; // 将所选内容设置为插入的最后一项 34 // pDoc->UpdateAllViews(NULL); 35 // } 36 // CATCH(CException, e) 37 // { 38 // if (pItem != NULL) 39 // { 40 // ASSERT_VALID(pItem); 41 // pItem->Delete(); 42 // } 43 // AfxMessageBox(IDP_FAILED_TO_CREATE); 44 // } 45 // END_CATCH 46 // 47 // EndWaitCursor(); 48 49 EmbedAutomateExcel(); 50 }
下面执行看下效果。
点击文件-退出
再点击取消
=======================================================================
要注意的是,部分安全软件,例如我的大Comodo会在HIPS和沙箱里拦截对COM口的访问,所以你懂的。
=======================================================================
=======================================================================
下一篇文章,将使用MFC的对话框程序实现内嵌Excel。
虽然实现了但还有些东西没弄好,为了部落的荣耀还是先写个SDI的放出来吧。
=======================================================================
文中示例代码在我的CSDN下载中http://download.csdn.net/detail/wlsgzl/8730199
不过,认真看文章跟着做的话基本不需要下载这个资源。
=======================================================================