⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 csdn_文档中心_activex control and it's container.htm

📁 csdn10年中间经典帖子
💻 HTM
📖 第 1 页 / 共 3 页
字号:
            strServerPath;<BR>CString strString;<BR>// 
            首先,清空列表框,并用m_aImplementCategories的数据填充pcatidImpl, 
            作为m_pCatInfo函数<BR>EnumClassedOfCategories的第二个参数,来获取CLSID的枚举器<BR>m_lbControls.ResetContent();<BR>nImplementCategories 
            = m_aImplementCategories.GetSize();<BR>if (nImplementCategories == 
            0) <BR>{<BR>&nbsp; nImplementCategories = (ULONG)-1;<BR>&nbsp; 
            pcatidImpl = NULL;<BR>}<BR>else<BR>{<BR>// 
            为pcatidImpl分配内存,将m_aImplementCategories数据传给pcatidImpl<BR>&nbsp; 
            pcatidImpl = (CATID*)_alloca(nImplementCategories * 
            sizeof(CATID));<BR>&nbsp; for ( iCategory = 0; iCategory &lt; 
            nImplementCategories; iCategory++)<BR>&nbsp; {<BR>&nbsp; 
            pcatidImpl[iCategory] = m_aImplementCategories[iCategory];<BR>&nbsp; 
            }<BR>}<BR>// 获取CLSID的枚举器<BR>hResult = 
            m_pCatInfo-&gt;EnumClassesOfCategories(nImplementCategories, 
            pcatidImpl, <BR>0, NULL, &amp;pEnum);<BR>if 
            (FAILED(hResult))<BR>&nbsp; return;<BR>// 然后通过枚举器枚举所有ActiveX 
            Control的CLSID, 并取得相应的用户类型名称,加入到列表框<BR>中.<BR>bDone = FALSE;<BR>while 
            (!bDone)<BR>{<BR>&nbsp; hResult = pEnum-&gt;Next(1, &amp;clsid, 
            NULL);&nbsp; // 获得下一个ActiveX Control的CLSID<BR>&nbsp; if (hResult == 
            S_OK)<BR>&nbsp; {<BR>&nbsp; pszName = NULL;<BR>&nbsp; hResult = 
            OleRegGetUserType(clsid, USERCLASSTYPE_FULL, 
            &amp;pszName);//得到相应的用户<BR>类型名称<BR>&nbsp; if 
            (SUCCEEDED(hResult))<BR>&nbsp; {<BR>&nbsp; &nbsp; strName = 
            pszName;<BR>&nbsp; &nbsp; CoTaskMemFree(pszName);<BR>&nbsp; &nbsp; 
            pszName = NULL;<BR>&nbsp; &nbsp; iItem = 
            m_lbControls.AddString(strName);<BR>&nbsp; &nbsp; posControl = 
            m_lControls.AddTail(clsid);<BR>&nbsp; &nbsp; 
            m_lbControls.SetItemDataPtr(iItem, posControl);<BR>&nbsp; 
            }<BR>&nbsp; }<BR>&nbsp; else<BR>&nbsp; {<BR>&nbsp; bDone = 
            TRUE;<BR>&nbsp; 
            }<BR>}<BR>OnControlsSelChange();<BR>}<BR><BR>上面这个函数演示了如何从众多的COM组件中提取ActiveX控件并把它们添加到一个列表框中,同时保<BR>留了它们的CLSID. 
            其中m_pCatInfo在InitDialog中调用CreateInstance创建自己的实例.<BR>&nbsp; 
            <BR>&nbsp; &nbsp; 在我们的到了某个ActiveX控件的CLSID以后, 
            我们就可以利用CoCreateInstanse函数来生成该<BR>控件的实例. 如上面所说的, 每一个ActiveX控件都有一个包装类, 
            我们在创建控件的时候, 实际上<BR>都是通过这个包装类来进行,下面我们看一下, 
            在这个包装类中创建控件的代码(删除了一些不是很重<BR>要的代码).<BR><BR><BR>BOOL 
            CActiveXContainerCntrItem::CreateControl(REFCLSID 
            clsid)<BR>{<BR>IUnknown* pUnknown;<BR>// 1. 创建控件自己的实例, 
            在下面的步骤将对控件的一些状态进行初始化&nbsp; &nbsp; <BR>HRESULT hResult = 
            CoCreateInstance(clsid, NULL, CLSCTX_INPROC&brvbar;CLSCTX_SERVER, 
            IID_IUnknown, (void**)&amp;pUnknown);<BR>if 
            (FAILED(hResult))<BR>&nbsp; return FALSE;<BR><BR>// 2. 
            在控件中请求IOleObject接口,&nbsp; &nbsp; <BR>hResult = 
            pUnknown-&gt;QueryInterface(IID_IOleObject, 
            (void**)&amp;m_lpObject);<BR>if (FAILED(hResult))<BR>{<BR>&nbsp; 
            pUnknown-&gt;Release();<BR>&nbsp; return 
            FALSE;<BR>}<BR>pUnknown-&gt;Release();<BR><BR>CString 
            strUserType;<BR>GetUserType(USERCLASSTYPE_SHORT, strUserType);<BR>// 
            3. 创建一个唯一的名称, 
            用来维护每个控件实例的唯一性<BR>GetDocument()-&gt;CreateUniqueItemName(this, 
            strUserType, m_strDisplayName);<BR><BR>// 4. 
            初始化控件的某些基本信息.<BR>InitControlInfo();<BR><BR>BOOL bQuickActivate = 
            FALSE;<BR>// 5. 如果控件支持IQuickActivate接口, 
            利用IQuickActive接口激活控件<BR>bQuickActivate = QuickActivate();<BR>if 
            (!bQuickActivate)<BR>{<BR>&nbsp; // 6. 如果控件不支持IQuickActiveX接口, 
            通过IOleObject接口设置控件的ClientSite.<BR>&nbsp; 
            m_lpObject-&gt;GetMiscStatus(DVASPECT_CONTENT, 
            &amp;m_dwMiscStatus);<BR>&nbsp; if (m_dwMiscStatus &amp; 
            OLEMISC_SETCLIENTSITEFIRST)<BR>&nbsp; hResult = 
            m_lpObject-&gt;SetClientSite(GetClientSite());<BR>&nbsp; if 
            (FAILED(hResult))<BR>&nbsp; TRACE0("Can't SetClientSite for the 
            Control\n");<BR>}<BR><BR>if (SUCCEEDED(hResult))<BR>{<BR>&nbsp; // 
            7. 支持IQuickActivate接口的控件必须使用下面的步骤.<BR>&nbsp; IPersistStreamInitPtr 
            pPersistStreamInit;<BR>&nbsp; IPersistStoragePtr 
            pPersistStorage;<BR><BR>&nbsp; pPersistStreamInit = 
            m_lpObject;<BR>&nbsp; if (pPersistStreamInit != NULL)<BR>&nbsp; 
            {<BR>&nbsp; hResult = pPersistStreamInit-&gt;InitNew();<BR>&nbsp; if 
            (hResult == E_NOTIMPL)<BR>&nbsp; &nbsp; hResult = S_OK;<BR>&nbsp; 
            }<BR>&nbsp; else<BR>&nbsp; {<BR>&nbsp; pPersistStorage = 
            m_lpObject;<BR>&nbsp; if (pPersistStorage != NULL)<BR>&nbsp; 
            {<BR>&nbsp; &nbsp; hResult = 
            pPersistStorage-&gt;InitNew(m_lpStorage);<BR>&nbsp; }<BR>&nbsp; 
            else<BR>&nbsp; {<BR>&nbsp; &nbsp; hResult = S_OK;<BR>&nbsp; 
            }<BR>&nbsp; }<BR>}<BR><BR>return FinishCreate(hResult); // 8. 
            在此处设置对控件的事件处理和属性处理信息<BR>}<BR><BR>下面针对上面注释中提到的一些内容进行说明, <BR>&nbsp; 
            &nbsp; 注释2请求IOleObject接口是用来对后面的一些设置做准备, 因为这个接口要在很多的地方使<BR>用, 
            所以被保存在一个成员变量中. <BR>&nbsp; &nbsp; 注释3是用来区别一个控件的多个实例, 这个方法被文档类实现, 
            它根据控件的名称和一个数字<BR>来维护同一种控件的实例.<BR>&nbsp; &nbsp; 
            注释4是用来初始化控件的一些基本信息,这些信息是通过读取控件类型库将控件的属性和事件放<BR>在各自的列表中, 
            以后好用来对控件的属性变化和事件进行响应.<BR>&nbsp; &nbsp; 注释5是针对QuickActivate()方法的, 
            QuickActivate()方法首先向控件请求IQuickActivate<BR>接口, 如果控件不支持该接口, 返回FALSE, 
            如果控件支持该接口, 则初始化两个结构QACONTAINER<BR>和QACONTROL, 
            然后用这两个结构调用IQuickActivate接口的QuickActivate方法, 
            <BR>IQuickActivate接口是为了提高ActiveX控件的加载速度而设计的.在调用了IQuickActivate接口的<BR>QuickActivate()方法之后, 
            IPersist*::Init和IPersist*::InitNew方法必须被调用, 
            控件应该<BR>在QuickActivate方法中建立它的连接点与容器的接收器之间的连接, 
            如果没有调用<BR>IPersist*::Init和IPersist*::InitNew, 
            那么这些连接就不会生效.<BR><BR>&nbsp; &nbsp; <BR>&nbsp; &nbsp; 到这里控件已经被建立了, 
            但是这里并没有涉及到与容器有关的内容. 下面讲述具体的容器的实<BR>现. 我们在例子中可以看到, 
            程序的文档类继承自COleDocument, 在COleDocument中文档为我们实<BR>现了作为容器所必须实现的一个接口, 
            IOleContainer, 我们在程序中可以通过GetStartPosition<BR>(), 
            GetNextItem()等方法来使用这个接口, 
            这个接口的主要作用是用来遍历容器中的控件或其他的<BR>OLE对象.另外还有一些必须实现的接口实际上已经在MFC中实现, 
            我们在一般情况下只要简单的使用<BR>这些经过封装的函数就可以了, 这里主要讲述一些与控件的属性和事件处理相关的一些问题, 
            在<BR>ActiveX控件及实现中我们提到, 控件的属性和事件一般是通过IDispatch来实现, 在Test 
            <BR>Container中我们可以看到下面的一段用来实现接口映射的代码.<BR><BR>BEGIN_INTERFACE_MAP( 
            CTestContainer98Item, COleClientItem )<BR>&nbsp; INTERFACE_PART( 
            CTestContainer98Item, IID_IServiceProvider, ServiceProvider 
            )<BR><BR>&nbsp; INTERFACE_PART( CTestContainer98Item, 
            IID_IPropertyNotifySink, PropertyNotifySink )<BR>&nbsp; 
            INTERFACE_PART( CTestContainer98Item, IID_IDispatch, 
            AmbientProperties )<BR>&nbsp; INTERFACE_PART( CTestContainer98Item, 
            IID_IOleControlSite, OleControlSite )<BR>//&nbsp; INTERFACE_PART( 
            CTestContainer98Item, IID_IOleInPlaceSiteEx, 
            OleInPlaceSiteWindowless )<BR>//&nbsp; INTERFACE_PART( 
            CTestContainer98Item, IID_IOleInPlaceSiteWindowless, 
            OleInPlaceSiteWindowless )<BR>END_INTERFACE_MAP()<BR>&nbsp; &nbsp; 
            <BR>我们可以看到, 在上面的接口映射中一共出现了6个接口, 但是有两个入口是被注释的. 
            下面我们逐<BR>一解释这些接口:<BR>&nbsp; &nbsp; 
            第一个IServiceProvider在这里主要是用来提供IBindHost接口的. 实际上在实现一个容器的时<BR>候, 
            这个接口并不是必须的. <BR><BR>&nbsp; &nbsp; 
            第二个IPropertyNotifySink是用来实现控件的属性变化通知的接收器. 
            如果希望你的容器能在<BR>其中的控件的属性改变时得到相应的通知, 
            就要实现这个接口,在这个接口的OnChange方法中你可以<BR>得到相应的被改编的属性的DISPID, 
            有了这个DISPID,你就可以更进一步的控制控件的某些属性特征<BR>了.<BR>&nbsp; &nbsp; 
            第三个接口是用来为控件提供环境属性的. 为控件提供环境属性这个功能是由IDispatch接口实<BR>现的, 
            每一个环境属性都具有特定的DISPID, 所以当控件调用GetAmbientxxx方法时, 
            控件就会要求<BR>容器提供相应的属性的实现,这些属性都是被IDispatch接口实现的.<BR><BR>&nbsp; &nbsp; 
            第四个接口是IOleControlSite. 这个接口的主要作用是提供一些在容器内部的Site对象对内嵌<BR>在其中的控件的管理. 
            实现这个接口是可选的.<BR><BR>&nbsp; &nbsp; 在上面的接口映射中, 我们并没有看到对控件的事件的处理的接口映射, 
            在Test Container的<BR>代码中我们可以看到下面这段代码.<BR>&nbsp; BEGIN_INTERFACE_PART( 
            EventHandler, IDispatch )<BR>&nbsp; STDMETHOD( GetIDsOfNames )( 
            REFIID iid, LPOLESTR* ppszNames, UINT nNames, LCID <BR>lcid, DISPID* 
            pDispIDs );<BR>&nbsp; STDMETHOD( GetTypeInfo )( UINT iTypeInfo, LCID 
            lcid, ITypeInfo** ppTypeInfo );<BR>&nbsp; STDMETHOD( 
            GetTypeInfoCount )( UINT* pnInfoCount );<BR>&nbsp; STDMETHOD( Invoke 
            )( DISPID dispidMember, REFIID iid, LCID lcid, WORD wFlags, 
            <BR>DISPPARAMS* pdpParams, VARIANT* pvarResult, EXCEPINFO* 
            pExceptionInfo, UINT* <BR>piArgError );<BR>&nbsp; 
            END_INTERFACE_PART( EventHandler )<BR>很显然这段代码是用来处理事件的, 
            但是为什么在接口的映射部分没有它呢? 
            如果你查看<BR>CTestContainer98Item类的代码时你会发现一个叫做GetInterfaceHook()的方法, 
            这个方法有一个<BR>类型为const void*的参数pv, 
            这个参数实际上是一个IID类型的指针,看看下面的代码:<BR>&nbsp; piid = (const 
            IID*)pv;<BR>&nbsp; if( *piid == m_infoEvents.GetIID() )<BR>&nbsp; 
            {<BR>&nbsp; &nbsp; &nbsp; return( &amp;m_xEventHandler );<BR>&nbsp; 
            }<BR>现在我们知道了控件的事件是怎么处理的, GetInterfaceHook()方法是CCmdTarget的一个方法, 
            但<BR>是在MSDN中却并没有文档说明.在这个方法中同样也实现了其他几个接口的映射关系.<BR><BR>&nbsp; &nbsp; 
            到这里我们已经可以了解到要实现一个ActiveX控件的容器所需要实现的接口及相关的一些问题<BR>了, 
            MFC的类库为我们做了许多的工作, 它们实现了一些作为控件容器所必须实现的接口, 
            使我们在<BR>开发这类应用程序的时候有了很好的起点.<BR><BR>4.总结<BR><BR>&nbsp; &nbsp; 
            上面所谈到的只是一些基本的概念及简单的实现, 开发一个ActiveX控件或者是它的容器都需要<BR>很多的知识和技术, 
            因为COM本身就是一项十分庞大的技术规范, 它涉及了很多方面的知识, 
          而这些<BR>又往往是其它基于COM的技术的基础.<BR><BR></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR>
<TABLE align=center bgColor=#006699 border=0 cellPadding=0 cellSpacing=0 
width=770>
  <TBODY>
  <TR bgColor=#006699>
    <TD align=middle bgColor=#006699 id=white><FONT 
    color=#ffffff>对该文的评论</FONT></TD>
    <TD align=middle>
      <SCRIPT 
      src="CSDN_文档中心_ActiveX Control and it's Container.files/readnum.htm"></SCRIPT>
    </TD></TR></TBODY></TABLE><BR>
<DIV align=center>
<TABLE align=center bgColor=#cccccc border=0 cellPadding=2 cellSpacing=1 
width=770>
  <TBODY>
  <TR>
    <TH bgColor=#006699 id=white><FONT 
color=#ffffff>我要评论</FONT></TH></TR></TBODY></TABLE></DIV>
<DIV align=center>
<TABLE border=0 width=770>
  <TBODY>
  <TR>
    <TD>你没有登陆,无法发表评论。 请先<A 
      href="http://www.csdn.net/member/login.asp?from=/Develop/read_article.asp?id=767">登陆</A> 
      <A 
href="http://www.csdn.net/expert/zc.asp">我要注册</A><BR></TD></TR></TBODY></TABLE></DIV><BR>
<HR noShade SIZE=1 width=770>

<TABLE border=0 cellPadding=0 cellSpacing=0 width=500>
  <TBODY>
  <TR align=middle>
    <TD height=10 vAlign=bottom><A 
      href="http://www.csdn.net/intro/intro.asp?id=2">网站简介</A> - <A 
      href="http://www.csdn.net/intro/intro.asp?id=5">广告服务</A> - <A 
      href="http://www.csdn.net/map/map.shtm">网站地图</A> - <A 
      href="http://www.csdn.net/help/help.asp">帮助信息</A> - <A 
      href="http://www.csdn.net/intro/intro.asp?id=2">联系方式</A> - <A 
      href="http://www.csdn.net/english">English</A> </TD>
    <TD align=middle rowSpan=3><A 
      href="http://www.hd315.gov.cn/beian/view.asp?bianhao=010202001032100010"><IMG 
      border=0 height=48 
      src="CSDN_文档中心_ActiveX Control and it's Container.files/biaoshi.gif" 
      width=40></A></TD></TR>
  <TR align=middle>
    <TD vAlign=top>百联美达美公司 版权所有 京ICP证020026号</TD></TR>
  <TR align=middle>
    <TD vAlign=top><FONT face=Verdana>Copyright &copy; CSDN.net, Inc. All rights 
      reserved</FONT></TD></TR>
  <TR>
    <TD height=15></TD>
    <TD></TD></TR></TBODY></TABLE></DIV>
<DIV></DIV><!--内容结束//--><!--结束//--></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -