ActiveX服务器

上传人:仙*** 文档编号:43750493 上传时间:2021-12-04 格式:DOC 页数:33 大小:88.51KB
返回 下载 相关 举报
ActiveX服务器_第1页
第1页 / 共33页
ActiveX服务器_第2页
第2页 / 共33页
ActiveX服务器_第3页
第3页 / 共33页
点击查看更多>>
资源描述
ActiveX服务器专业知识库 2009-06-01 14:14:04 阅读36 评论0 字号:大中小 所谓服务器,就是一些应用程序或者动态链接库,它们可以被容器调用,完成特定的功能。ActiveX服务器大体上分为三种:全服务器,小型服务器和自动化服务器。全服务器不仅是一个ActiveX服务器,而且是一个可以独立运行的应用程序。比如Word就是这样的例子。它不但可以被其它的容器程序所调用生成服务器对象,而且它本身就是一个完整的容器程序。小型服务器是指该服务器不能独立运行,只有把自己包括进另一个应用程序之中才可以使用。自动化服务器可能是最重要的一种服务器了,它和小型服务器、全服务器有很大的不同。自动化服务器是可以由其它应用程序编程驱动的组件。这种服务器提供特殊的对象、方法和属性使你可以告诉它去做什么。自动化服务器必须至少含有一个IDispatch接口。它可以有自己的界面,当然也可以不要自己的界面。自动化服务器有两种类型:进程内服务器和进程外服务器。一个进程内服务器是由一个存储在DLL中的类创建的,并由创建服务器的应用程序加载,服务器在应用程序的进程控件内运行,所有的实例共享同一代码。而一个进程外服务器在它自己的地址控件内运行,这种服务器一般建立成EXE应用程序,可以管理多个实例或者在创建每个服务器对象时启动一个EXE的新拷贝。与自动化服务器相对应的是自动化控制器,自动化控制器可以通过编程来控制自动化服务器,象我们常用的VB就是典型的自动化控制器。接下来,我们将有重点的讨论如何定制ActiveX服务器。定制小型服务器这一节,我们来定制一个小型服务器,并且以一个EXE应用程序来生成。它是可以内嵌于容器的,在容器中,它将画一个圆,圆的位置可以用鼠标点击来调整。如图13.1,把该服务器插入到写字板中,这里插入了三次,三个圆处于不同的位置。当要调整其位置时,可以双击服务器对象,激活它,然后用鼠标左键点击,这时,圆将在新的位置重新画出。 1生成基本框架 从VC的主窗口中选择File菜单下的New 菜单项,打开Projects标签,选择MFC AppWizar d(EXE)项目,设置正确的路径(Location)和项目名称,我们这里在Project name编辑框中填入MiniServer,如图13.2。按下OK按钮,进入第一步,在这里,我们只简单的选择单文档Single Document即可,如图13.3。按下Next按钮。在第二步中,如果没有特殊的要求,不需要作任何改变,再次按下Next按钮。小型服务器的运行情况 建立MiniServer项目选择单文档 接下来出现的第三步是最重要的,在这里我们要选择所建立的服务器的类型,确保选中Mini-Server复选框,如图13.4,这表明我们使用的复合文档类型是小型服务器。在前面定制ActiveX容器时,我们曾经选用的是Container选项。同时,在这里,你同样可以选择全服务器(Full-Server)、容器-服务器(Both Container and Server)等。你还可以选择你的服务器是否支持自动化(Automation)或者ActiveX控件(ActiveX Controls)。在这里,我们只是演示如何构建一个小型服务器,不打算支持自动化,在后面的自动化服务器一节会作更为详细的介绍。选择小型服务器按Next进入第四步,在这里,我们修改一些高级的选项,按下Advanced按钮,则会弹出Advanced Options对话框,如图13.5。在File type ID编辑框中填入MiniServer.Document,这个字符串作为一个标示,当客户应用程序(client application)使用该服务器时,它会使用该标示来创建服务器对象或者存取服务器对象的接口。在Filetype name编辑框内填入MiniServer Demo,该字符串将显示在标准的插入对象对话框的对象类型列表框内(你可以在Word或者写字板等容器程序中找到)。最后,按Close按钮,退出当前的高级选项对话框。高级选项对话框现在已经完成了必要的设置,下面的接受默认值,选择Finish,退出MFC AppWizard(EXE)向导。2分析MFC向导生成的代码 让我们看一下MFC向导生成了哪些重要的类和文件。1、MiniServer.h这个文件定义了类CMiniServerApp,在这个类中,多出了一个重要的成员变量: COleTemplateServer m_server这个变量是类COleTemplateServer的对象,一个服务器应用程序中支持的服务器文档必须对应一个COleTemplateServer对象。2、MiniServer.cpp这是类CMiniServerApp的实现文件。它定义了一个CLSID: / 204F59C3-B2BD-11D2-BC00-48540000048E static const CLSID clsid = 0x204f59c3, 0xb2bd, 0x11d2, 0xbc, 0x0, 0x48, 0x54, 0x0, 0x0, 0x4, 0x8e ; 这个值用来识别我们生成的COM类。在这个文件中,最重要的要算InitInstance()成员函数了,该函数在类初始化服务器实例时被调用,让我们分析一下它不同于一般应用程序的地方。首先,在函数的开始部分,初始化OLE动态链接库,这是涉及OLE操作时必须进行的一步: if (!AfxOleInit() AfxMessageBox(IDP_OLE_INIT_FAILED); return FALSE; 在生成新的文档模板,但未注册之前,调用SetServerInfo()函数,该函数的原型如下:void SetServerInfo( UINT nIDOleEmbedding, UINT nIDOleInPlaceServer = 0, CRun timeClass* pOleFrameClass = NULL, CRuntimeClass* pOleViewClass = NULL ); nIDOleEmbedding: 当嵌入对象被单独的窗口编辑时使用的资源 nIDOleInPlaceServer: 当嵌入对象在位激活时使用的资源 pOleFrameClass: 当发生在位激活时,容器将根据这个CRuntimeClass结构的信息,生 成一个相应的在位激活框架类的对象 pOleViewClass: 当发生在位激活时,容器将根据这个CRuntimeClass结构的信息,生 成一个相应的在位激活视图类的对象实际的实现为:pDocTemplate-SetServerInfo( IDR_SRVR_EMBEDDED, IDR_SRVR_INPLACE, RUNTIME_CLASS(CInPlaceFrame); 它表示独立窗口编辑时使用菜单IDR_SRVR_EMBEDDED,在位激活时使用菜单IDR_SRVR_IN PLACE,并且在位激活时,生成一个CInPlaceFrame对象。我们在稍后一些介绍类CInPla ceFrame。 函数使用下面语句来连结文档模板到COleTemplateServer 对象m_server上去: m_server.ConnectTemplate(clsid, pDocTemplate, TRUE) COleTemplateServer使用文档模板中的信息来为容器程序创建新的文档。 最后,InitInstance()成员函数检查服务器是否是从嵌入模式中运行,如果是,则调用 RegisterAll()函数注册该服务器程序中所有的对象加工厂(object factory),而容器 程序在得到这些注册信息之后,就可以利用它来生成(加工)新的对象。在我们所建立 的小型服务器中,实际上是生成了一个COleTemplateServer对象(它是直接从类COleOb jectFactory中继承而来的,这是一个很重要的类,如果想了解其详细的信息,请参阅联 机文档或相关资料)。如果服务器不是从嵌入模式中运行,使用UpdateRegistry(OAT_I NPLACE_SERVER)更新服务器的注册信息,然后提示用户该服务器之内从一个容器程序中 执行,因为它不支持独立执行: m_server.UpdateRegistry(OAT_INPLACE_SERVER); AfxMessageBox(IDP_USE_INSERT_OBJECT); 3、MiniServerDoc.h 该文件包含了类CMiniServerDoc的定义,这个类在嵌入式服务器中是至关重要的,在后 面,你会体会到这一点。它还定义了一个成员函数: CMiniServerSrvrItem* GetEmbeddedItem() return (CMiniServerSrvrItem*)COleServerDoc:GetEmbeddedItem(); 这个函数可以返回一个文档的指针,而在这里,它什么都没有做,你可以修改这个函数 ,以返回必要的信息。 4、MiniServerDoc.cpp 这个文件包含了CMiniServerDoc类的实现部分。 在类的构造函数CMiniServerDoc()中调用EnableCompoundFile()来使该类可以处理复合 文档: CMiniServerDoc:CMiniServerDoc() / Use OLE compound files EnableCompoundFile(); / TODO: add one-time construction code here 当在容器中插入一个服务器对象或者已有的服务器对象在位激活时,将调用成员函数函 数OnGetEmbeddedItem(),在向导生成的代码中,没有做进一步的处理,只是简单的通知 类加工厂(Class Factory)来调用,而生成了一个CMiniServerSrvrItem对象(参考后 面的部分): COleServerItem* CMiniServerDoc:OnGetEmbeddedItem() / OnGetEmbeddedItem is called by the framework to get the COleServerItem / that is associated with the document. It is only called when necessary . CMiniServerSrvrItem* pItem = new CMiniServerSrvrItem(this); ASSERT_VALID(pItem); return pItem; 同时,还给出了函数Serialize()的实现代码: void CMiniServerDoc:Serialize(CArchive& ar) if (ar.IsStoring() / TODO: add storing code here else / TODO: add loading code here 当容器程序有序列化操作时,被插入到容器程序中的嵌入对象会调用这个函数。这样, 如果你的服务器有自己的设置或者数据,则可以调用此函数,把它们保存到容器的数据 中去或者从容器的数据读取出来。 5、MainFrm.h和MainFrm.cpp 这两个文件定义了类CMainFrame以及其基本的实现。当你不选择在位激活而是在单独的 窗口中编辑对象时,将会创建CMainFrame对象。在本程序中由于只支持在位激活,所以 该对象即使被创建,也不会做任何事。 6、MiniServerView.h和MiniServerView.cpp 这两个文件实现了服务器的画图,需要注意的是,这里的画图只输出给服务器的框架窗 口;如果不做其它处理,当退出服务器时(嵌入对象不再激活),容器中将什么都看不 到。具体如何操作,请见后面部分。要注意到,在文件MiniServerView.cpp中,有一个 很重要的函数: CMiniServerDoc* CMiniServerView:GetDocument() / non-debug version is inlin e ASSERT(m_pDocument-IsKindOf(RUNTIME_CLASS(CMiniServerDoc); return (CMiniServerDoc*)m_pDocument; 它返回一个CMiniServerDoc指针,这个指针可用来对与服务器相对应的文档进行必要的 操作。 另一个函数是OnDraw()函数: void CMiniServerView:OnDraw(CDC* pDC) CMiniServerDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); / TODO: add draw code for native data here 通过该函数,你可以绘制服务器对象在被激活时的外观表现。 还有一个函数也要引起注意: void CMiniServerView:OnCancelEditSrvr() GetDocument()-OnDeactivateUI(FALSE); 如果处在在位激活状态,按下ESC键,该函数将被调用,以退出在位激活状态,这几乎成 了一个标准的操作。 7、SrvrItem.h和SrvrItem.cpp 文件SrvrItem.h和SrvrItem.cpp定义了类CMiniServerSrvrItem及其实现。当一个MiniS erver项被嵌入到容器中时,容器将会创建一个新的CMiniServerSrvrItem对象(关于容 器具体的创建过程,可以参考前面的ActiveX容器一章)。 在文件SrvrItem.h中,定义了一个函数: CMiniServerDoc* GetDocument() const return (CMiniServerDoc*)COleServerItem:GetDocument(); 它同样返回一个CMiniServerDoc文档指针,与上面提到的类CMiniServerView返回的是同 一个指针,因而可以利用这一点在服务器对象和容器之间传递数据。 在文件SrvrItem.cpp中,定义了几个重要的函数: void CMiniServerSrvrItem:Serialize(CArchive& ar) / CMiniServerSrvrItem:Serialize will be called by the framework if / the item is copied to the clipboard. This can happen automatically / through the OLE callback OnGetClipboardData. A good default for / the embedded item is simply to delegate to the documents Serialize / function. If you support links, then you will want to serialize / just a portion of the document. if (!IsLinkedItem() CMiniServerDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); pDoc-Serialize(ar); 当容器要存储一个带有内嵌服务器对象的文档时,它会调用上面的函数来保存数据。MF C向导生成的代码只是简单地调用了CMiniServerDoc的Serialize()函数;此时,数据被 存储到一个容器提供的永久存储对象之中,而不序列化到一个文件。如果,你不想这么 做,那么可以编写自己的代码放在上面,把数据存放到单独的文件。在某些情况下,这 是很重要的,如对于很大的图片,你也许会设计一种自己的存放格式或者压缩格式,单 独存放。 BOOL CMiniServerSrvrItem:OnDraw(CDC* pDC, CSize& rSize) / Remove this if you use rSize UNREFERENCED_PARAMETER(rSize); CMiniServerDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); / TODO: set mapping mode and extent / (The extent is usually the same as the size returned from OnGetExtent) pDC-SetMapMode(MM_ANISOTROPIC); pDC-SetWindowOrg(0,0); pDC-SetWindowExt(3000, 3000); / TODO: add drawing code here. Optionally, fill in the HIMETRIC extent. / All drawing takes place in the metafile device context (pDC). return TRUE; OnDraw()函数由容器来调用。容器通过调用该函数,把MiniServer嵌入对象绘制在一个 特殊的设备环境中(元设备环境)。绘制的结果就是嵌入对象未激活时在容器中的样子 。一般来说,类CMiniServerSrvrItem和类CMiniServerView的OnDraw()函数的结果应该 一致,如在容器中插入一个画图对象(Bmp对象),我们希望在退出画图时,保持绘 制结果。我们在后面会用具体的代码使该函数绘制的结果和CMiniServerView的OnDraw( )函数绘制的结果一致。 BOOL CMiniServerSrvrItem:OnGetExtent(DVASPECT dwDrawAspect, CSize& rSize) / Most applications, like this one, only handle drawing the content / aspect of the item. If you wish to support other aspects, such / as DVASPECT_THUMBNAIL (by overriding OnDrawEx), then this / implementation of OnGetExtent should be modified to handle the / additional aspect(s). if (dwDrawAspect != DVASPECT_CONTENT) return COleServerItem:OnGetExtent(dwDrawAspect, rSize); / CMiniServerSrvrItem:OnGetExtent is called to get the extent in / HIMETRIC units of the entire item. The default implementation / here simply returns a hard-coded number of units. CMiniServerDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); / TODO: replace this arbitrary size rSize = CSize(3000, 3000); / 3000 x 3000 HIMETRIC units return TRUE; OnGetExtent()函数由容器程序来调用,通过调用该函数,容器来确定嵌入对象的尺寸。 由MFC向导创建的代码使用一个固定的尺寸:3000x3000,它所使用的是HIMETRIC单位。 8、IpFrame.h和IpFrame.cpp 这两个文件定义了类CInPlaceFrame及其实现。类CInPlaceFrame管理在位激活。对于容 器中的嵌入对象,在位激活(in-place activation)扮演着重要的角色。当用户把一 个OLE项嵌入到容器中后,可能需要随时编辑它。 (MSDN Topic: Activation) 在文件IpFrame.h的类CInPlaceFrame定义中,有三个成员变量应该引起注意: CToolBar m_wndToolBar; COleDropTarget m_dropTarget; COleResizeBar m_wndResizeBar; m_wndToolBar: 指向一个工具条,当在位激活时,它会取代容器的工具条 m_dropTarget: 该对象被用来使服务器对象处理拖曳操作,不过,由于无任何可执行代 码,所以不会有任何动作。但是其想法是为了保证容器中的所有嵌入对象都应该对拖曳 操作做出反应,而不会使拖曳操作中断。至于如何处理拖曳操作,在ActiveX容器一章有 详细的描述,请参照。 m_wndResizeBar:这是一个尺寸缩放框对象,当一个OLE嵌入对象产生时,将会创建该对 象与之相对应。 下面,我们来看文件IpFrame.cpp中的几个函数。 int CInPlaceFrame:OnCreate(LPCREATESTRUCT lpCreateStruct) if (COleIPFrameWnd:OnCreate(lpCreateStruct) = -1) return -1; / CResizeBar implements in-place resizing. if (!m_wndResizeBar.Create(this) TRACE0(Failed to create resize barn); return -1; / fail to create / By default, it is a good idea to register a drop-target that does / nothing with your frame window. This prevents drops from / falling through to a container that supports drag-drop. m_dropTarget.Register(this); return 0; OnCreate()函数创建在位框架窗口、尺寸缩放框,并且注册了拖曳操作。 BOOL CInPlaceFrame:OnCreateControlBars(CFrameWnd* pWndFrame, CFrameWnd* pWn dDoc) / Remove this if you use pWndDoc UNREFERENCED_PARAMETER(pWndDoc); / Set owner to this window, so messages are delivered to correct app m_wndToolBar.SetOwner(this); / Create toolbar on clients frame window if (!m_wndToolBar.CreateEx(pWndFrame, TBSTYLE_FLAT,WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) | !m_wndToolBar.LoadToolBar(IDR_SRVR_INPLACE) TRACE0(Failed to create toolbarn); return FALSE; / TODO: Delete these three lines if you dont want the toolbar to / be dockable m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); pWndFrame-EnableDocking(CBRS_ALIGN_ANY); pWndFrame-DockControlBar(&m_wndToolBar); return TRUE; 函数OnCreateControlBars在容器的窗口内创建一个工具条,而取代容器原来的工具条。 它也是一个普通的工具条,与以前所见的并无多大区别。对于上面各个语句的具体功能 ,请参照前面的有关章节。 9、MiniServer.rc 这个文件包含了服务器程序需要的资源。我们注意有两个菜单资源: IDR_ SRVR_EMBEDDED IDR_SRVR_INPLACE 当服务器对象在单独的窗口中被编辑时,使用IDR_ SRVR_EMBEDDED菜单,而在在位激活 时,IDR_SRVR_INPLACE菜单将和容器中原有的一部分菜单合并到一起。在IDR_SRVR_INP LACE菜单中,如果有两个分界条,容器菜单合并到分界条之间,否则合并到编辑之前 。 13.2.3定制MiniServer 我们已经对一个小型服务器的结构有了一个全面的了解。现在来定制我们自己的服务器 ,虽然它的功能比较简单(前面提到过,我们只是简单的画一个圆),但是可以从中领 略到定制一个小型服务器的整个过程。 1定制类CMiniServerDoc 类CMiniServerDoc在服务器程序中充当了重要的角色。因为它可以为类CMiniServerVie w所调用,又可以被类CMiniServerSrvrItem所调用,这样就提供给我们一条传递数据的 途径。前面曾经说过,服务器对象的激活状态和非激活状态的绘制,是由不同的绘图函 数来完成的,因而有必要给类CMiniServerDoc添加一个绘图函数: void DrawCircle(CDC *pDC,RECT *pRect,POINT *pPoint); 以及相关的成员变量: CBitmap *m_pBitmap; CBitmap *m_pOldBitmap; POINT m_CircleCenter; RECT m_rcViewRect; CDC * m_pMemoryDC; 现对成员变量说明如下: m_pBitmap: 与设备相关联的位图 m_pOldBitmap: 保存原有的设备位图 m_CircleCenter: 圆心坐标 m_rcViewRect: 服务器视图的范围 m_pMemoryDC: 一个内存设备环境,它保存服务器视图中绘制的内容 而函数DrawCircle()定义如下: void CMiniServerDoc: DrawCircle(CDC *pDC,RECT *pRect,POINT *pPoint) pDC-Ellipse(pPoint-x-20,pPoint-y-20,pPoint-x+20,pPoint-y+20); 可以看出,它只是画了一个固定大小的圆。其中,参数pPoint是圆心坐标,而pRect指出 了绘图的区域,实际上并没有用到,但是传递该参数在某些时候显然是必要的。 最后,不要忘了在构造函数中初始化成员变量: CMiniServerDoc:CMiniServerDoc() / Use OLE compound files EnableCompoundFile(); /成员变量初始化 m_pBitmap=m_pOldBitmap=NULL; m_pMemoryDC=NULL; m_CircleCenter.x=m_CircleCenter.y=0; m_rcViewRect=CRect(0,0,3000,3000); 2定制类CMiniServerView 下面,我们给类CMiniServerView添加一个WM_LBUTTONDOWN消息的处理函数,因为我们将 在鼠标点击的位置画一个圆。 对于具体的添加过程这里不再讨论,如有必要,参考前面的有关章节;当添加完成后, 其函数原型为(在文件MiniServerView.cpp中可以找到): void CMiniServerView:OnLButtonDown(UINT nFlags, CPoint point) / TODO: Add your message handler code here and/or call default CView:OnLButtonDown(nFlags, point); 我们作如下的修改: void CMiniServerView:OnLButtonDown(UINT nFlags, CPoint point) CMiniSvrDoc* pDoc = GetDocument(); pDoc-m_CircleCenter=point; InvalidateRect(NULL); pDoc-UpdateAllViews(NULL); CView:OnLButtonDown(nFlags, point); 它先保存鼠标的点击位置,然后强制重画。这样,就会调用类CMiniServerView的成员函 数OnDraw(),而我们就可以在OnDraw()函数中利用这个点画出相应的圆。 于是,我们修改OnDraw()函数如下(在文件MiniServerView.cpp中): void CMiniServerView:OnDraw(CDC* pDC) CMiniServerDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if(pDoc-m_pMemoryDC!=NULL) pDoc-m_pMemoryDC-SelectObject(pDoc-m_pOldBitmap); pDoc-m_pMemoryDC-DeleteDC(); delete pDoc-m_pBitmap; delete pDoc-m_pMemoryDC; GetClientRect(&pDoc-m_rcViewRect); pDoc-m_pMemoryDC=new CDC(); pDoc-m_pBitmap=new CBitmap(); pDoc-m_pMemoryDC-CreateCompatibleDC(pDC); pDoc-m_pBitmap-CreateCompatibleBitmap(pDC, pDoc-m_rcViewRect.right-pDoc-m_rcViewRect.left, pDoc-m_rcViewRect.bottom-pDoc-m_rcViewRect.top); pDoc-m_pOldBitmap=pDoc-m_pMemoryDC-SelectObject(pDoc-m_pBitmap); pDoc-DrawCircle(pDC,&pDoc-m_rcViewRect, &pDoc-m_CircleCenter); pDoc-m_pMemoryDC-BitBlt( pDoc-m_rcViewRect.left, pDoc-m_rcViewRect.top, pDoc-m_rcViewRect.right, pDoc-m_rcViewRect.bottom, pDC,0,0,SRCCOPY); pDoc-UpdateAllItems(NULL); 在这里不打算详细讨论上面的各个语句的具体含义,只把其流程说明如下: 清除原来的内存DC和位图; 创建新的内存DC和位图; 画圆(斜体部分); 在内存DC中保存绘制的结果; 最后调用UpdateAllItems来使得文档通知所有服务器文档自身重画 3定制类MiniServerSrvrItem 在这个类中,我们修改它的OnDraw()函数如下: BOOL CMiniServerSrvrItem:OnDraw(CDC* pDC, CSize& rSize) / Remove this if you use rSize UNREFERENCED_PARAMETER(rSize); CMiniServerDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); / TODO: set mapping mode and extent / (The extent is usually the same as the size returned from OnGetExtent) pDC-SetMapMode(MM_ANISOTROPIC); pDC-SetWindowOrg(0,0); pDC-SetWindowExt(3000, 3000); CRect rect; rect.TopLeft()=pDC-GetWindowOrg(); rect.BottomRight()=pDC-GetWindowExt()+rect.TopLeft(); if(pDoc-m_pMemoryDC!=NULL) if(pDC-StretchBlt(rect.left,rect.top, rect.right-rect.left, rect.bottom-rect.top, pDoc-m_pMemoryDC,0,0, pDoc-m_rcViewRect.right-pDoc-m_rcViewRect.left, pDoc-m_rcViewRect.bottom-pDoc-m_rcViewRect.top, SRCCOPY)=FALSE) return FALSE; return TRUE; 至此,我们的定制已经全部完成,对服务器编译连结之后,你就可以使用它了,可惜的 是,它的功能太弱。如何给它强大的功能,应该是你自己的工作了。 13.2.4测试 现在你可以使用我们前面所编写的ActiveX容器程序来测试这个小型服务器了,如图13. 6。当嵌入对象被激活时,点击鼠标左键,则会在相应的位置绘制一个固定大小的圆;而 当按下ESC键后,则退出在位编辑,这时,容器中的圆的位置正确的反映了编辑的结果。 如果在WordPad(写字板)中进行测试,主要的结果应该相同,不过,写字板并不是一个 完善的容器,退出在位编辑以后,对象在服务器中的位置并不能反映到写字板中。 测试小型服务器 13.2.5其它问题 注册该小型服务器 服务器只有被注册以后,才可以被容器程序使用。在MFC向导生成的文件中,有一个文件 :MiniServer.reg,你可以使用该文件进行注册,具体做法是: 运行RegEdit.exe程序(这个程序在你的Windows系统目录下),选择注册表菜单下的 引入注册表文件菜单项,选择MiniServer.reg文件即可。如图13.7。 服务器注册 另外,因为我们的小型服务器是EXE类型的,所以可以直接运行它,前面我们分析过,它 虽然报错退出,但是已经把自己进行注册了。实际上,你可以编制自己的代码代替程序 中的报错警告(即:AfxMessageBox(IDP_USE_INSERT_OBJECT),这个函数在文件Mini Server.cpp中可以找到),而显示自己的注册提示,这样就很自然的注册了该服务器, 而且不会出现令人讨厌的警告。 当然,更进一步,你还可以编制自己的安装程序,直接存取注册表,这里不作更详细的 讨论。 关于用ATL创建小型服务器 一个小型服务器也可以用ActiveX模板库(ATL)来创建,但是我们这里不作深入探讨, 而把重点放在自动化服务器上。有兴趣的读者可以查看联机帮助中的有关文档和给出的 一部分例子。 定制全服务器 关于全服务器,它的定制和小型服务器没有大的差别,所以在这里把具体的操作过程留 给读者,只不过要记住,在MFC AppWizard(EXE)的第三步中,要选择Full Server,如图 13.8所示。 选择全服务器 定制自动化服务器 Visual C+ 6.0为我们提供了方便的工具来开发自动化服务器,你可以使用MFC或者ATL 来进行自己的工作。下面我们分别介绍。 13.4.1用MFC设计进程内自动化服务器 下面我们来设计一个进程内服务器,它拥有一个Radius属性和一个ShowMyDlg方法。Rad ius属性保存一个圆的半径的大小,而ShowMyDlg将显示一个对话框,在这个对话框中有 鼠标点击事件发生时,会在相应的位置绘制一个圆,而圆的大小就是使用Radius属性的 值。 1生成基本框架 从VC的主窗口中选择File菜单下的New 菜单项,打开Projects标签,选择MFC AppWizar d(dll)项目(我们以动态链接库的形式来创建自己的自动化服务器),设置正确的路径 (Location)和项目名称,我们这里在Project name编辑框中填入AutoDllMFC,如图13.9 ,然后按OK按钮确认。 AppWizard会弹出一个对话框(而对于动态链接库,AppWizard仅提供这一步操作)让你 选择必要的选项。在这里我们只需要改变动态链接库(DLL)的features为Automation, 即选中Automation复选框。如图13.10。 建立AutoDllMFC项目 支持自动化 然后按Finish按钮,确认。 2分析AppWizard创建的代码 文件:AutoDllMFC.odl (AutoClick Tu: Analyzing AppWizard-Provided Code: ODL File for Creating a Type Library) 文件:AutoDllMFC.cpp 它的InitInstance函数增加了注册代码,正如注释中所说的,通过注册所有在运行的服 务器,其它的应用程序就可以从中创建对象: BOOL CAutoDllMFCApp:InitInstance() / Register all OLE server (factories) as running. This enables the / OLE libraries to create objects from other applications. COleObjectFactory:RegisterAll(); return TRUE; 同时,本文件中包含了AppWizard自动创建的三个函数,并且在模块定义文件AutoDllMF C.def中定义为对外输出函数。 / / / Special entry points required for inproc servers STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) AFX_MANAGE_STATE(AfxGetStaticModuleState(); return AfxDllGetClassObject(rclsid, riid, ppv); STDAPI DllCanUnloadNow(void) AFX_MANAGE_STATE(AfxGetStaticModuleState(); return AfxDllCanUnloadNow(); / by exporting DllRegisterServer, you can use regsvr.exe STDAPI DllRegisterServer(void) AFX_MANAGE_STATE(AfxGetStaticModuleState(); COleObjectFactory:UpdateRegistryAll(); return S_OK; 说明如下: DllGetClassObject: 提取对象接口,以创建对象 DllCanUnloadNow : 判断DLL是否可以卸载 DllRegisterServer: 注册服务器 这三个函数都可以由外部程序所调用,来完成对服务器对象的操作。 3定制AutoDllMFC自动化服务器 作为一个自动化服务器,必需含有至少一个基于IDispatch的接口。而该接口可以由类C CmdTarget来实现。选择Class View标签,用右键点击AutoDllMFC classes,在鼠标菜单 中选择New class,则弹出New Class对话框,如图13.11。填入以下内容: Name: MyDisp Base class: CCmdTarget Automation: Createable by type ID: AutoDllMFC.MyDisp 这里,我们选择Automation的Createable by type ID单选钮,是为了使其有更好的可读 性,在下面的测试中,你会看到它的作用。 添加MyDisp类 打开AutoDllMFC.odl文件,可以看到这里已经添加了一个基于IDispatch的接口IMyDisp : / Primary dispatch interface for MyDisp uuid(84961804-B36A-11D2-BC00-48540000048E) dispinterface IMyDisp properties: / NOTE - ClassWizard will maintain property information here. / Use extreme caution when editing this section. /AFX_ODL_PROP(MyDisp) /AFX_ODL_PROP methods: / NOTE - ClassWizard will maintain method information here. / Use extreme caution when editing this section. /AFX_ODL_METHOD(MyDisp) /AFX_ODL_METHOD ; 现在,它还没有属性和方法,后面我们将依次添加。 同时,coclass接口定义你的类加工厂接口。类加工厂是应用程序的一部分,负责实现生 成自动化服务器: / Class information for MyDisp uuid(84961805-B36A-11D2-BC00-48540000048E) coclass MyDisp default dispinterface IMyDisp; ; /AFX_APPEND_ODL /AFX_APPEND_ODL 打开MyDisp.h文件,在这个文件中,包含了新定义的类MyDisp。在这个类中,添加了一 个重要的宏: DECLARE_OLECREATE() 所有ActiveX组件都是由被称为类加工厂的对象生成的。MFC定义了类COleObjectFactor y作为其对类加工厂的支持。上面的宏中就定义了一个COleObjectFactory对象,这些可 以查看宏定义得知。当然,对于具体的细节,可以不去理会。 在文件MyDisp.h文件中,添加了另一个宏: IMPLEMENT_OLECREATE() 这个宏用来创建服务器对象。 下面让我们来为该服务器添加一个新的方法ShowMyDlg。当完成该方法的定制以后,其效 果是:运行该方法,显示一个模态对话框,你可以在对话框用鼠标中点击,在相应的位 置将画出一个圆。 首先,创建一个对话框资源,删除上面所有的控件(VC会自动生成两个按钮控件),并 且适当调整其
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 压缩资料 > 基础医学


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!