单文档/视图结构的ActiveX控件

单文档/视图结构的ActiveX控件

单文档/视图模式是MFC编程里比较强大的一种编程模式,如果ActiveX控件能够用这种模式的话,将可以做出非常强大的Web在线应用。
下面我们就介绍一种把单文档/视图模式的程序改造成ActiveX控件的方法。
做起来很难,但是完成了会很有成就感,本方法来源于15Seconds。 在VC6.0和VC.Net下都已证明可行。我用这个方法做了一个Web上的在线服装设计软件,Client端支持NT4.0,客户公司有上千台NT4.0。据美国同事说在投标中击败了Altium公司(电路设计软件Protel的开发商)的方案,哈。
需要要两个文件:
1.ActivDoc.cpp

// 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* pParentWnd)
{
    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_ALL
 return 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 document

    CCreateContext 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);
        else
            m_pOnlyDoc->SetModifiedFlag(FALSE);
    }

}


/**//////
// CActiveXDocControl

IMPLEMENT_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_MAP
    ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()
BEGIN_DISPATCH_MAP(CActiveXDocControl, COleControl)
    //{{AFX_DISPATCH_MAP(CActiveXDocControl)
    
//}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()
BEGIN_EVENT_MAP(CActiveXDocControl, COleControl)
    //{{AFX_EVENT_MAP(COleFrameCtrl)
    
//}}AFX_EVENT_MAP
END_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* pDocTemplate)
{
    // 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.h

class 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_EVENT

    DECLARE_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替换COleControl
3.把ActivDoc.h和ActivDoc.cpp加入工程中
4.ActivDoc.h头文件加入MyActiveXCrtl文件的头部
5.拷贝单文档视图的文件(框架文件(*frm.cpp,*frm.h),文档文件(*doc.cpp,*doc.h),视图文件(*view.cpp,*view.h),和其他.cpp和.h,注意,不包括App文件)到ActiveX工程。
6.把这些文件加入工程,在这些文件头部加入App头文件的包含,(不做)

并在MyActiveXCrtl文件的头部加入这些头文件包含,如果StdAfx.h有不同,需要手工合并。
7.手工把单文档视图工程的资源文件合并到ActiveX工程的资源文件中(应该不难吧,把两个资源文件用编辑器打开,把变量,对话框,类等等全部合并,不过这是个细活,哈)。

先把自己的单文档项目中的res文件夹拷贝到ActiveX工程中,

把自己的单文档项目中的Resource.h中的内容复制到ActiveX工程的Resource.h中,保存Resource。

把test.rc(自己的单文档项目的.rs文件)拷贝到ActiveX工程中,在ActiveX工程点添加,现有项,选.rc  然后资源中会出现test.rc  直接把test.rc中的各个资源复制到MyActiveX.rc中

8.把单文档视图工程的classWizard(*.clw)文件合并到ActiveX工程中(方法同上,用编辑器打开两个文件手工合并)。(vs2013 不做)
9.在框架文件中加入定义:(没做)

 class CActiveToolBar : public CToolBar
 {
     LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
 
 public:
     BOOL Create(CWnd* pParentWnd);
 }
;

 和动作:

 BOOL CActiveToolBar::Create(CWnd* pParentWnd)
 {
     if (!CToolBar::Create(pParentWnd) || !LoadToolBar(IDR_MAINFRAME))
         return FALSE;
 
     // Remove this if you don't want tool tips
 
     SetBarStyle(GetBarStyle() |    CBRS_TOOLTIPS |
         CBRS_FLYBY | CBRS_SIZE_FIXED);
 
    
     return TRUE;
 }

 
 LRESULT CActiveToolBar::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
 {
     
     MSG msg;
     msg.hwnd = m_hWnd;
     msg.message = message;
     msg.wParam = wParam;
     msg.lParam = lParam;
 
     GetCursorPos(&msg.pt);
     FilterToolTipMessage(&msg);
 
     return CToolBar::WindowProc(message,wParam,lParam);
 }

10.把框架文件中用到的sCStatusBar和CSplitterWnd删除,并把ToolBar的类型改为CActiveToolBar,(没做)
 例如:CToolBar m_ToolBar; 改为CActiveToolBar m_ToolBar;

11.把框架文件的oncreate改为类似:(不做)

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 
 {
  if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
   return -1;
  
  // TODO: Add your specialized creation code here
 
   if (!m_ToolBar.Create(this))
      {
          TRACE0("Failed to create toolbar ");
          return -1;
      }

  
      return 0;
 }

12.利用classWizard给控件(*ctrl)的Automation中加入成员变量 DocumentName,产生onchange动作:(不做)

 void MyMiniDrawCtrl::OnDocumentNameChanged() 
 {
  // TODO: Add notification handler code
  GetDocTemplate()->OpenDocumentFile(m_documentName);
      SetModifiedFlag();
 }

13.同上加入Stock-BorderStyle.(不做)
14.删除控件的OnDraw动作,把构造函数改为,类似以下:

  MyMiniDrawCtrl::MyMiniDrawCtrl()
 {
  InitializeIIDs(&IID_DMyMiniDraw, &IID_DMyMiniDrawEvents);
 
   // TODO: Initialize your control's instance data here.
   SetInitialSize(200, 200);

  AddDocTemplate(new CActiveXDocTemplate(
  RUNTIME_CLASS(CMinidrawDoc),   //改为你的文档类
  RUNTIME_CLASS(CMainFrame),  //改为你的框架类
  RUNTIME_CLASS(CMinidrawView))); //改为你的视图类
 }



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值