==================================聲明==================================
本文版權歸作者所有
未經作者授權 請勿轉載 保留法律追究的權利
本文原創,已獲得轉載授權的,必須在正文中顯要地注明作者和出處,並保證文章(包括本聲明)的完整性。
被授權人不可再次授權第三方。
未經作者授權請勿修改(包括本聲明),保留法律追究的權利。
未經作者授權請勿用於學術性引用。
未經作者授權請勿用於商業出版、商業印刷、商業引用以及其他商業用途。 <--------總有一天我要自己做一個模板干掉這只土豆
本文不定期修正完善,為保證內容正確,建議移步原文處閱讀。
本文鏈接: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
不過,認真看文章跟着做的話基本不需要下載這個資源。
=======================================================================