当前位置:文档之家› 单文档视图结构ActiveX控件

单文档视图结构ActiveX控件

单文档/视图模式是MFC编程里比较强大的一种编程模式,如果ActiveX控件能够用这种模式的话,将可以做出非常强大的Web在线应用。

下面我们就介绍一种把单文档/视图模式的程序改造成ActiveX控件的方法。

做起来很难,但是完成了会很有成就感,本方法来源于15Seconds。

在VC6.0和下都已证明可行。

我用这个方法做了一个Web上的在线服装设计软件,Client 端支持NT4.0,客户公司有上千台NT4.0。

据美国同事说在投标中击败了Altium公司(电路设计软件Protel的开发商)的方案,哈。

需要要两个文件:// ActivDoc.cpp : implementation file//#include "stdafx.h"#include "ActivDoc.h"CActiveXDocTemplate::CActiveXDocTemplate(CRuntimeClass* pDocClass, CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass): CSingleDocTemplate(IDR_NOTUSED, pDocClass, pFrameClass,pViewClass){ASSERT(pFrameClass);}CFrameWnd* CActiveXDocTemplate::CreateDocViewFrame(CWnd* pParen tWnd){CWaitCursor cursor;TRY{ASSERT(pParentWnd && IsWindow(*pParentWnd));ASSERT_KINDOF(CActiveXDocControl, pParentWnd);m_pParentWnd = pParentWnd;m_pFrameWnd = NULL;// OpenDocumentFile is a virtual method (implemented in// the CSingleDocTemplate base class) that creates// the document (either empty or loaded from the specified// file) and calls our CreateNewFrame function. Passing// NULL to the function creates a new document. Incidentally,// the view is created by the CFrameWnd's OnCreateClient()// method.if (!OpenDocumentFile(NULL))return NULL;// Since OpenDocumentFile sets m_pFrame, we can now use it.ASSERT(m_pFrameWnd);ASSERT_KINDOF(CFrameWnd, m_pFrameWnd);m_pFrameWnd->ShowWindow(SW_SHOWNORMAL);return m_pFrameWnd;}CATCH_ALL(e){AfxMessageBox("Read storyboard error.please retry!");//THROW_LAST();}END_CATCH_ALLreturn NULL;}CFrameWnd* CActiveXDocTemplate::CreateNewFrame(CDocument* pDoc, CFrameWnd* pOther){ASSERT(pOther == NULL);ASSERT(m_pFrameClass != NULL);if (pDoc != NULL)ASSERT_VALID(pDoc);// Create a frame wired to the specified documentCCreateContext context;context.m_pCurrentFrame = pOther;context.m_pCurrentDoc = pDoc;context.m_pNewViewClass = m_pViewClass;context.m_pNewDocTemplate = this;m_pFrameWnd = (CFrameWnd*)m_pFrameClass->CreateObject();if (m_pFrameWnd == NULL){TRACE1("Warning: Dynamic create of frame %hs failed. ",m_pFrameClass->m_lpszClassName);return NULL;}ASSERT_KINDOF(CFrameWnd, m_pFrameWnd);if (context.m_pNewViewClass == NULL)TRACE0("Warning: creating frame with no default view. ");// The frame is created as a menu-less child of the// CActiveXDocControl in which it will reside.ASSERT_KINDOF(CActiveXDocControl, m_pParentWnd);if (!m_pFrameWnd->Create(NULL, "", WS_CHILD|WS_VISIBLE, CFrameWnd::rectDefault, m_pParentWnd, NULL, 0, &context)) {TRACE0("Warning: CDocTemplate couldn't create a frame. ");return NULL;}return m_pFrameWnd;}CDocument* CActiveXDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName, BOOL bVerifyExists){CWaitCursor cursor;SaveDocumentFile();m_docFile = lpszPathName;if (bVerifyExists){DWORD dwAttrib = GetFileAttributes(m_docFile);if (dwAttrib == 0xFFFFFFFF ||dwAttrib == FILE_ATTRIBUTE_DIRECTORY){lpszPathName = NULL;}}return CSingleDocTemplate::OpenDocumentFile(lpszPathName, TRUE);}void CActiveXDocTemplate::SaveDocumentFile(){if (m_pOnlyDoc != NULL){if (!m_docFile.IsEmpty())m_pOnlyDoc->OnSaveDocument(m_docFile);elsem_pOnlyDoc->SetModifiedFlag(FALSE);}}///////////////////////////////////////////////////////////////////////////// // CActiveXDocControlIMPLEMENT_DYNAMIC(CActiveXDocControl, COleControl)BEGIN_MESSAGE_MAP(CActiveXDocControl, COleControl) //{{AFX_MSG_MAP(CActiveXDocControl)ON_WM_CREATE()ON_WM_SIZE()ON_WM_TIMER()ON_WM_DESTROY()//}}AFX_MSG_MAPON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)END_MESSAGE_MAP()BEGIN_DISPATCH_MAP(CActiveXDocControl, COleControl) //{{AFX_DISPATCH_MAP(CActiveXDocControl)//}}AFX_DISPATCH_MAPEND_DISPATCH_MAP()BEGIN_EVENT_MAP(CActiveXDocControl, COleControl)//{{AFX_EVENT_MAP(COleFrameCtrl)//}}AFX_EVENT_MAPEND_EVENT_MAP()int CActiveXDocControl::m_bDocInitialized = FALSE; CActiveXDocControl::CActiveXDocControl(){CWaitCursor cursor;m_pDocTemplate = NULL;m_pFrameWnd = NULL;// Since we're in an OCX, CWinApp::InitApplication() is// not called by the framework. Unfortunately, that method// performs CDocManager initialization that is necessary// in order for our DocTemplate to clean up after itself.// We simulate the same initialization by calling the// following code the first time we create a control.if (!m_bDocInitialized){CDocManager docManager;docManager.AddDocTemplate(NULL);m_bDocInitialized = TRUE;}}CActiveXDocControl::~CActiveXDocControl(){// Note that the frame, the document, and the view are// all deleted automatically by the framework!KillTimer(m_Timer);delete m_pDocTemplate;m_bDocInitialized = FALSE;}void CActiveXDocControl::AddDocTemplate(CActiveXDocTemplate* pDocT emplate){// I've decided to call this function AddDocTemplate to// be consistent with naming of CWinApp::AddDocTemplate.// However, only one DocTemplate is allowed per control.CWaitCursor cursor;ASSERT(pDocTemplate);ASSERT(m_pDocTemplate == NULL);m_pDocTemplate = pDocTemplate;}int CActiveXDocControl::OnCreate(LPCREATESTRUCT lpCreateStruct) {CWaitCursor cursor;if (COleControl::OnCreate(lpCreateStruct) == -1)return -1;// The CActiveXDocTemplate object will create the// document, the view, and the frame inside the// control. The reason we need a handle to the frame// is so that we can resize it when the control is// resized.ASSERT(m_pDocTemplate); // Set in call to AddDocTemplate m_pFrameWnd = m_pDocTemplate->CreateDocViewFrame(this); ASSERT_KINDOF(CFrameWnd, m_pFrameWnd);// By default, we'll create the control with a border,// since it looks better for frames containing a toolbar.SetBorderStyle(TRUE);m_IsTimerEnd = "NO";m_Timer = SetTimer(WM_IDLEUPDATECMDUI, 300, NULL);return 0;}void CActiveXDocControl::OnSize(UINT nType, int cx, int cy){COleControl::OnSize(nType, cx, cy);// The CFrameWnd should always fill up the entire client// area of the control.if (m_pFrameWnd != NULL){ASSERT(IsWindow(*m_pFrameWnd));CRect area;GetClientRect(area);m_pFrameWnd->MoveWindow(area.left, area.top, area.right, area.bottom);}}void CActiveXDocControl::OnTimer(UINT nIDEvent){// Since we're in an OCX, we don't control the message loop,// so CWinThread::OnIdle is never called. That means we have // to periodically pump the ON_UPDATE_COMMAND_UI messages // by hand.SendMessageToDescendants(WM_IDLEUPDATECMDUI, TRUE);//COleControl::OnTimer(nIDEvent);/*if (m_IsTimerEnd=="NO") {m_IsTimerEnd = "YES";}*/}void CActiveXDocControl::OnDestroy(){AfxGetApp()->m_pMainWnd = NULL;m_pDocTemplate->SaveDocumentFile();COleControl::OnDestroy();}2. ActivDoc.hclass CActiveXDocTemplate : public CSingleDocTemplate{enum { IDR_NOTUSED = 0x7FFF };CWnd* m_pParentWnd;CFrameWnd* m_pFrameWnd;CString m_docFile;public:CActiveXDocTemplate(CRuntimeClass* pDocClass,CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass);CFrameWnd* CreateDocViewFrame(CWnd* pParentWnd);void SaveDocumentFile();virtual CFrameWnd* CreateNewFrame(CDocument* pDoc,CFrameWnd* pOther);virtual CDocument* OpenDocumentFile(LPCTSTR lpszPathName, BOOL bVerifyExists = TRUE);};///////////////////////////////////////////////////////////////////////////// class CActiveXDocControl : public COleControl{enum { WM_IDLEUPDATECMDUI = 0x0363 };CActiveXDocTemplate* m_pDocTemplate;UINT m_Timer;DECLARE_DYNAMIC(CActiveXDocControl)protected:void AddDocTemplate(CActiveXDocTemplate* pDocTemplate);CDocTemplate* GetDocTemplate() { return m_pDocTemplate; } CString m_IsTimerEnd;//{{AFX_MSG(CActiveXDocControl)afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);afx_msg void OnSize(UINT nType, int cx, int cy);afx_msg void OnTimer(UINT nIDEvent);afx_msg void OnDestroy();//}}AFX_MSG//{{AFX_DISPATCH(CActiveXDocControl)//}}AFX_DISPATCH//{{AFX_EVENT(CActiveXDocControl)//}}AFX_EVENTDECLARE_MESSAGE_MAP()DECLARE_DISPATCH_MAP()DECLARE_EVENT_MAP()public:CActiveXDocControl();virtual ~CActiveXDocControl();CFrameWnd* m_pFrameWnd;static BOOL m_bDocInitialized;enum {//{{AFX_DISP_ID(CActiveXDocControl)//}}AFX_DISP_ID};};改造步骤:1.建立MFC ActiveX工程(例如:MyActiveX)2.用CActiveXDocControl替换COleControl3.把ActivDoc.h和ActivDoc.cpp加入工程中5.拷贝单文档视图的文件(框架文件(*frm.cpp,*frm.h),文档文件(*doc.cpp,*doc.h),视图文件(*view.cpp,*view.h),和其他.cpp和.h,注意,不包括App文件)到ActiveX工程。

相关主题