魔改——MFC SDI 支持 內嵌 EXCEL OLE


==================================聲明==================================

本文版權歸作者所有

未經作者授權 請勿轉載 保留法律追究的權利

本文原創,已獲得轉載授權的,必須在正文中顯要地注明作者和出處,並保證文章(包括本聲明)的完整性。

被授權人不可再次授權第三方。

未經作者授權請勿修改(包括本聲明),保留法律追究的權利。

未經作者授權請勿用於學術性引用。

未經作者授權請勿用於商業出版、商業印刷、商業引用以及其他商業用途。                    <--------總有一天我要自己做一個模板干掉這只土豆

 

本文不定期修正完善,為保證內容正確,建議移步原文處閱讀。

本文鏈接: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

不過,認真看文章跟着做的話基本不需要下載這個資源。

 

 

 

 

 

 

=======================================================================

恥辱牆 http://www.cnblogs.com/wlsandwho/p/4206472.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM