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

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

None.gif //  ActivDoc.cpp : implementation file
None.gif
//
None.gif

None.gif#include 
" stdafx.h "
None.gif#include 
" ActivDoc.h "
None.gif
None.gifCActiveXDocTemplate::CActiveXDocTemplate(CRuntimeClass
*  pDocClass,
None.gif    CRuntimeClass
*  pFrameClass, CRuntimeClass *  pViewClass)
None.gif        : CSingleDocTemplate(IDR_NOTUSED, pDocClass, pFrameClass,
None.gif            pViewClass)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    ASSERT(pFrameClass);
ExpandedBlockEnd.gif}

None.gif
None.gifCFrameWnd
*  CActiveXDocTemplate::CreateDocViewFrame(CWnd *  pParentWnd)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    CWaitCursor cursor;
InBlock.gif TRY
ExpandedSubBlockStart.gifContractedSubBlock.gif 
dot.gif{
InBlock.gif ASSERT(pParentWnd 
&& IsWindow(*pParentWnd));
InBlock.gif    ASSERT_KINDOF(CActiveXDocControl, pParentWnd);
InBlock.gif    m_pParentWnd 
= pParentWnd;
InBlock.gif    m_pFrameWnd 
= NULL;
InBlock.gif
InBlock.gif    
// OpenDocumentFile is a virtual method (implemented in
InBlock.gif    
// the CSingleDocTemplate base class) that creates
InBlock.gif    
// the document (either empty or loaded from the specified
InBlock.gif    
// file) and calls our CreateNewFrame function. Passing
InBlock.gif    
// NULL to the function creates a new document. Incidentally,
InBlock.gif    
// the view is created by the CFrameWnd's OnCreateClient()
InBlock.gif    
// method.
InBlock.gif

InBlock.gif    
if (!OpenDocumentFile(NULL))
InBlock.gif       
return NULL;
InBlock.gif
InBlock.gif    
// Since OpenDocumentFile sets m_pFrame, we can now use it.
InBlock.gif

InBlock.gif    ASSERT(m_pFrameWnd);
InBlock.gif    ASSERT_KINDOF(CFrameWnd, m_pFrameWnd);
InBlock.gif    m_pFrameWnd
->ShowWindow(SW_SHOWNORMAL);
InBlock.gif    
return m_pFrameWnd;
ExpandedSubBlockEnd.gif }

InBlock.gif CATCH_ALL(e)
ExpandedSubBlockStart.gifContractedSubBlock.gif 
dot.gif{
InBlock.gif  AfxMessageBox(
"Read storyboard error.please retry!");
InBlock.gif  
//THROW_LAST();
ExpandedSubBlockEnd.gif
 }

InBlock.gif END_CATCH_ALL
InBlock.gif 
return NULL;
ExpandedBlockEnd.gif}

None.gif
None.gifCFrameWnd
*  CActiveXDocTemplate::CreateNewFrame(CDocument *  pDoc,
None.gif        CFrameWnd
*  pOther)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    ASSERT(pOther 
== NULL);
InBlock.gif    ASSERT(m_pFrameClass 
!= NULL);
InBlock.gif    
if (pDoc != NULL)
InBlock.gif        ASSERT_VALID(pDoc);
InBlock.gif
InBlock.gif    
// Create a frame wired to the specified document
InBlock.gif

InBlock.gif    CCreateContext context;
InBlock.gif    context.m_pCurrentFrame 
= pOther;
InBlock.gif    context.m_pCurrentDoc 
= pDoc;
InBlock.gif    context.m_pNewViewClass 
= m_pViewClass;
InBlock.gif    context.m_pNewDocTemplate 
= this;
InBlock.gif
InBlock.gif    m_pFrameWnd 
= (CFrameWnd*)m_pFrameClass->CreateObject();
InBlock.gif    
if (m_pFrameWnd == NULL)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        TRACE1(
"Warning: Dynamic create of frame %hs failed. ",
InBlock.gif            m_pFrameClass
->m_lpszClassName);
InBlock.gif        
return NULL;
ExpandedSubBlockEnd.gif    }

InBlock.gif    ASSERT_KINDOF(CFrameWnd, m_pFrameWnd);
InBlock.gif
InBlock.gif    
if (context.m_pNewViewClass == NULL)
InBlock.gif        TRACE0(
"Warning: creating frame with no default view. ");
InBlock.gif
InBlock.gif    
// The frame is created as a menu-less child of the
InBlock.gif    
// CActiveXDocControl in which it will reside.
InBlock.gif

InBlock.gif    ASSERT_KINDOF(CActiveXDocControl, m_pParentWnd);
InBlock.gif    
if (!m_pFrameWnd->Create(NULL, "", WS_CHILD|WS_VISIBLE,
InBlock.gif        CFrameWnd::rectDefault, m_pParentWnd, NULL, 
0&context))
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        TRACE0(
"Warning: CDocTemplate couldn't create a frame. ");
InBlock.gif        
return NULL;
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
return m_pFrameWnd;
ExpandedBlockEnd.gif}

None.gif
None.gifCDocument
*  CActiveXDocTemplate::OpenDocumentFile(
None.gif    LPCTSTR lpszPathName, BOOL bVerifyExists)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    CWaitCursor cursor;
InBlock.gif SaveDocumentFile();
InBlock.gif    m_docFile 
= lpszPathName;
InBlock.gif
InBlock.gif    
if (bVerifyExists)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        DWORD dwAttrib 
= GetFileAttributes(m_docFile);
InBlock.gif        
if (dwAttrib == 0xFFFFFFFF ||
InBlock.gif            dwAttrib 
== FILE_ATTRIBUTE_DIRECTORY)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            lpszPathName 
= NULL;
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
return CSingleDocTemplate::OpenDocumentFile(
InBlock.gif        lpszPathName, TRUE);
ExpandedBlockEnd.gif}

None.gif
None.gif
void  CActiveXDocTemplate::SaveDocumentFile()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
if (m_pOnlyDoc != NULL)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
if (!m_docFile.IsEmpty())
InBlock.gif            m_pOnlyDoc
->OnSaveDocument(m_docFile);
InBlock.gif        
else
InBlock.gif            m_pOnlyDoc
->SetModifiedFlag(FALSE);
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**/ /////
None.gif //  CActiveXDocControl
None.gif

None.gifIMPLEMENT_DYNAMIC(CActiveXDocControl, COleControl)
None.gifBEGIN_MESSAGE_MAP(CActiveXDocControl, COleControl)
None.gif    
// {{AFX_MSG_MAP(CActiveXDocControl)
None.gif
    ON_WM_CREATE()
None.gif    ON_WM_SIZE()
None.gif    ON_WM_TIMER()
None.gif    ON_WM_DESTROY()
None.gif    
// }}AFX_MSG_MAP
None.gif
    ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
None.gifEND_MESSAGE_MAP()
None.gifBEGIN_DISPATCH_MAP(CActiveXDocControl, COleControl)
None.gif    
// {{AFX_DISPATCH_MAP(CActiveXDocControl)
None.gif    
// }}AFX_DISPATCH_MAP
None.gif
END_DISPATCH_MAP()
None.gifBEGIN_EVENT_MAP(CActiveXDocControl, COleControl)
None.gif    
// {{AFX_EVENT_MAP(COleFrameCtrl)
None.gif    
// }}AFX_EVENT_MAP
None.gif
END_EVENT_MAP()
None.gif
None.gif
int  CActiveXDocControl::m_bDocInitialized  =  FALSE;
None.gif
None.gifCActiveXDocControl::CActiveXDocControl()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    CWaitCursor cursor;
InBlock.gif m_pDocTemplate 
= NULL;
InBlock.gif    m_pFrameWnd 
= NULL;
InBlock.gif
InBlock.gif    
// Since we're in an OCX, CWinApp::InitApplication() is
InBlock.gif    
// not called by the framework. Unfortunately, that method
InBlock.gif    
// performs CDocManager initialization that is necessary
InBlock.gif    
// in order for our DocTemplate to clean up after itself.
InBlock.gif    
// We simulate the same initialization by calling the
InBlock.gif    
// following code the first time we create a control.
InBlock.gif

InBlock.gif    
if (!m_bDocInitialized)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        CDocManager docManager;
InBlock.gif        docManager.AddDocTemplate(NULL);
InBlock.gif        m_bDocInitialized 
= TRUE;
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
None.gifCActiveXDocControl::
~ CActiveXDocControl()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
// Note that the frame, the document, and the view are
InBlock.gif    
// all deleted automatically by the framework!
InBlock.gif
    KillTimer(m_Timer);
InBlock.gif    delete m_pDocTemplate;
InBlock.gif m_bDocInitialized 
= FALSE;
ExpandedBlockEnd.gif}

None.gif
None.gif
void  CActiveXDocControl::AddDocTemplate(CActiveXDocTemplate *  pDocTemplate)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
// I've decided to call this function AddDocTemplate to
InBlock.gif    
// be consistent with naming of CWinApp::AddDocTemplate.
InBlock.gif    
// However, only one DocTemplate is allowed per control.
InBlock.gif
    CWaitCursor cursor;
InBlock.gif
InBlock.gif    ASSERT(pDocTemplate);
InBlock.gif    ASSERT(m_pDocTemplate 
== NULL);
InBlock.gif    m_pDocTemplate 
= pDocTemplate;
ExpandedBlockEnd.gif}

None.gif
None.gif
int  CActiveXDocControl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    CWaitCursor cursor;
InBlock.gif 
if (COleControl::OnCreate(lpCreateStruct) == -1)
InBlock.gif        
return -1;
InBlock.gif
InBlock.gif    
// The CActiveXDocTemplate object will create the
InBlock.gif    
// document, the view, and the frame inside the
InBlock.gif    
// control. The reason we need a handle to the frame
InBlock.gif    
// is so that we can resize it when the control is
InBlock.gif    
// resized.
InBlock.gif
    
InBlock.gif    ASSERT(m_pDocTemplate);    
// Set in call to AddDocTemplate
InBlock.gif
    m_pFrameWnd = m_pDocTemplate->CreateDocViewFrame(this);
InBlock.gif    ASSERT_KINDOF(CFrameWnd, m_pFrameWnd);
InBlock.gif
InBlock.gif    
// By default, we'll create the control with a border,
InBlock.gif    
// since it looks better for frames containing a toolbar.
InBlock.gif

InBlock.gif    SetBorderStyle(TRUE);
InBlock.gif m_IsTimerEnd 
= "NO";
InBlock.gif    m_Timer 
= SetTimer(WM_IDLEUPDATECMDUI, 300, NULL);
InBlock.gif    
return 0;
ExpandedBlockEnd.gif}

None.gif
None.gif
void  CActiveXDocControl::OnSize(UINT nType,  int  cx,  int  cy) 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    COleControl::OnSize(nType, cx, cy);
InBlock.gif
InBlock.gif    
// The CFrameWnd should always fill up the entire client
InBlock.gif    
// area of the control.
InBlock.gif

InBlock.gif    
if (m_pFrameWnd != NULL)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        ASSERT(IsWindow(
*m_pFrameWnd));
InBlock.gif        CRect area;
InBlock.gif        GetClientRect(area);
InBlock.gif        m_pFrameWnd
->MoveWindow(area.left, area.top, area.right,
InBlock.gif            area.bottom);
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
None.gif
void  CActiveXDocControl::OnTimer(UINT nIDEvent) 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
// Since we're in an OCX, we don't control the message loop,
InBlock.gif    
// so CWinThread::OnIdle is never called. That means we have
InBlock.gif    
// to periodically pump the ON_UPDATE_COMMAND_UI messages
InBlock.gif    
// by hand.
InBlock.gif
    
InBlock.gif SendMessageToDescendants(WM_IDLEUPDATECMDUI, TRUE);
InBlock.gif 
//COleControl::OnTimer(nIDEvent);
ExpandedSubBlockStart.gifContractedSubBlock.gif
 /**//*if (m_IsTimerEnd=="NO") {
InBlock.gif     
InBlock.gif  m_IsTimerEnd = "YES";
ExpandedSubBlockEnd.gif }
*/

ExpandedBlockEnd.gif}

None.gif
None.gif
None.gif
void  CActiveXDocControl::OnDestroy() 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    AfxGetApp()
->m_pMainWnd = NULL;
InBlock.gif    m_pDocTemplate
->SaveDocumentFile();
InBlock.gif    COleControl::OnDestroy();
ExpandedBlockEnd.gif}

None.gif
None.gif


2. ActivDoc.h

None.gif class  CActiveXDocTemplate :  public  CSingleDocTemplate
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif    
enum dot.gif{ IDR_NOTUSED = 0x7FFF };
InBlock.gif
InBlock.gif    CWnd
* m_pParentWnd;
InBlock.gif CFrameWnd
* m_pFrameWnd;    
InBlock.gif    CString m_docFile;
InBlock.gif
InBlock.gif
public:
InBlock.gif
InBlock.gif    CActiveXDocTemplate(CRuntimeClass
* pDocClass,
InBlock.gif        CRuntimeClass
* pFrameClass, CRuntimeClass* pViewClass);
InBlock.gif
InBlock.gif    CFrameWnd
* CreateDocViewFrame(CWnd* pParentWnd);
InBlock.gif    
void SaveDocumentFile();
InBlock.gif
InBlock.gif    
virtual CFrameWnd* CreateNewFrame(CDocument* pDoc,
InBlock.gif        CFrameWnd
* pOther);
InBlock.gif    
virtual CDocument* OpenDocumentFile(
InBlock.gif        LPCTSTR lpszPathName, BOOL bVerifyExists 
= TRUE);
ExpandedBlockEnd.gif}
;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
/**/ /////
None.gif
None.gif
class  CActiveXDocControl :  public  COleControl
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif    
enum dot.gif{ WM_IDLEUPDATECMDUI = 0x0363 };
InBlock.gif
InBlock.gif    CActiveXDocTemplate
* m_pDocTemplate;
InBlock.gif
InBlock.gif UINT m_Timer;
InBlock.gif
InBlock.gif    DECLARE_DYNAMIC(CActiveXDocControl)
InBlock.gif
InBlock.gif
protected:
InBlock.gif    
void AddDocTemplate(CActiveXDocTemplate* pDocTemplate);
ExpandedSubBlockStart.gifContractedSubBlock.gif    CDocTemplate
* GetDocTemplate() dot.gifreturn m_pDocTemplate; }
InBlock.gif CString m_IsTimerEnd;
InBlock.gif
InBlock.gif    
//{{AFX_MSG(CActiveXDocControl)
InBlock.gif
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
InBlock.gif    afx_msg 
void OnSize(UINT nType, int cx, int cy);
InBlock.gif    afx_msg 
void OnTimer(UINT nIDEvent);
InBlock.gif    afx_msg 
void OnDestroy();
InBlock.gif    
//}}AFX_MSG
InBlock.gif    
//{{AFX_DISPATCH(CActiveXDocControl)
InBlock.gif    
//}}AFX_DISPATCH
InBlock.gif    
//{{AFX_EVENT(CActiveXDocControl)
InBlock.gif    
//}}AFX_EVENT
InBlock.gif

InBlock.gif    DECLARE_MESSAGE_MAP()
InBlock.gif    DECLARE_DISPATCH_MAP()
InBlock.gif    DECLARE_EVENT_MAP()
InBlock.gif
InBlock.gif
public:
InBlock.gif    CActiveXDocControl();
InBlock.gif    
virtual ~CActiveXDocControl();
InBlock.gif    CFrameWnd
* m_pFrameWnd;
InBlock.gif    
static BOOL m_bDocInitialized;
ExpandedSubBlockStart.gifContractedSubBlock.gif    
enum dot.gif{
InBlock.gif    
//{{AFX_DISP_ID(CActiveXDocControl)
InBlock.gif    
//}}AFX_DISP_ID
ExpandedSubBlockEnd.gif
    }
;
ExpandedBlockEnd.gif}
;
None.gif
None.gif


改造步骤:
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工程的资源文件中(应该不难吧,把两个资源文件用编辑器打开,把变量,对话框,类等等全部合并,不过这是个细活,哈)。
8.把单文档视图工程的classWizard(*.clw)文件合并到ActiveX工程中(方法同上,用编辑器打开两个文件手工合并)。
9.在框架文件中加入定义:

None.gif   class  CActiveToolBar :  public  CToolBar
ExpandedBlockStart.gifContractedBlock.gif 
dot.gif {
InBlock.gif     LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
InBlock.gif 
InBlock.gif 
public:
InBlock.gif     BOOL Create(CWnd
* pParentWnd);
ExpandedBlockEnd.gif }
;

 和动作:

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

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

None.gif

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

11.把框架文件的oncreate改为类似:

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

InBlock.gif  
InBlock.gif      
return 0;
ExpandedBlockEnd.gif }

None.gif

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

None.gif   void  MyMiniDrawCtrl::OnDocumentNameChanged() 
ExpandedBlockStart.gifContractedBlock.gif 
dot.gif {
InBlock.gif  
// TODO: Add notification handler code
InBlock.gif
  GetDocTemplate()->OpenDocumentFile(m_documentName);
InBlock.gif      SetModifiedFlag();
ExpandedBlockEnd.gif }

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

None.gif   MyMiniDrawCtrl::MyMiniDrawCtrl()
ExpandedBlockStart.gifContractedBlock.gif 
dot.gif {
InBlock.gif  InitializeIIDs(
&IID_DMyMiniDraw, &IID_DMyMiniDrawEvents);
InBlock.gif 
InBlock.gif   
// TODO: Initialize your control's instance data here.
InBlock.gif
   SetInitialSize(200200);
InBlock.gif
InBlock.gif  AddDocTemplate(
new CActiveXDocTemplate(
InBlock.gif  RUNTIME_CLASS(CMinidrawDoc),   
//改为你的文档类
InBlock.gif
  RUNTIME_CLASS(CMainFrame),  //改为你的框架类
InBlock.gif
  RUNTIME_CLASS(CMinidrawView))); //改为你的视图类
ExpandedBlockEnd.gif
 }

None.gif

转载于:https://www.cnblogs.com/rukeefan/archive/2004/08/08/31184.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值