魔改——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实现一下。

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

万一哪天我忘了怎么弄这个,还能找找自己的博客,顺便感叹下自己曾经也是魔改——MFC SDI 支持 内嵌 EXCEL OLE的。

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

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

你可能感兴趣的:(Excel)