万星星@豌豆荚 欢迎加入我们
一个吃软饭的男人!!!!!我只想写程序####
微博:http://weibo.com/wanlianwen
posts - 172,  comments - 1253,  trackbacks - 0

用一个没有任何意义的例子来看看com控件的创建过程。又是狠狠忙了一阵子。前几天,一个网上的朋友找到我,他想在richedit里面插入一个ax控件,这个倒是很简单,网上也很多。接下来,他想要在richedit里面插入一个窗口,当然无论ax控件是否设置m_bWindowOnly都无法达到需求。我给他的答案是不行,其实我不知道该如何解释这个问题。不管需求如何怪异,也不管是否解决了他的问题,这里我单纯来强行插入一个窗口到richedit,不关心插入进去是否可以正常工作。声明,这是一个没有意义的事情,只是想说明com控件创建过程。

一个支持com控件的窗口必须创建CWnd的COleControlContainer* m_pCtrlCont;  // for containing OLE controls,通过BOOL InitControlContainer();函数,它又会调用虚函数virtual BOOL CreateControlContainer(COleControlContainer** ppContainer);你可以重载来创建你自己的Container。而这个冬冬就好比一个宾馆,每个控件好比一个人,有人生自由,可以入住任何一个宾馆,但是一旦寄宿在一家宾馆,这个宾馆必须为之提供一个房间,这是ControlSite的概念,创建调用:
virtual BOOL CreateControlSite(COleControlContainer* pContainer, 
      COleControlSite
** ppSite, UINT nID, REFCLSID clsid);
这个这个宾馆的房间有多豪华就是你宾馆的星级,当然你可以通过重载这个函数来定制你的房间设施。
再通过:
virtual HRESULT CreateControl(CWnd* pWndCtrl, REFCLSID clsid,
        LPCTSTR lpszWindowName, DWORD dwStyle, 
const POINT* ppt,
      
const SIZE* psize, UINT nID, CFile* pPersist=NULL, BOOL bStorage=FALSE,
创建com控件。

我们有时候看见这样的创建方式:CWnd::CreateControl()来创建com控件。这其中经历了父窗口初始化ControlContainer,准备一个ControlSite,把com控件创建并安排到此房间并做一些初始化操作,然后把com控件窗口句柄(如果存在)依附到CWnd,这里CWnd充当的是一个与控件通信的代理。可以看出是否创建有窗口还是无窗口的,依赖CreateControl内部操作。再控件里面,我们看到控件实现了这样两个接口:
COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless)
 COM_INTERFACE_ENTRY(IOleInPlaceObject)
他们接口大同小异,一个是有窗口方式一个是无窗口方式,为什么这么做是历史原因,因为窗口耗费大量资源。在不深究下去,有兴趣可以找点老古典来瞅瞅。

下面开始我的创建过程:
我想实现在RichEdit里面创建一个房间(ControlSite)来容纳一个web控件,由于COleControlSite不让我new出来,所以我的继承一个CMyOleControlSite:
class CMyOleControlSite : public COleControlSite
{
public:
    CMyOleControlSite(COleControlContainer
* pCtrlCont) : COleControlSite(pCtrlCont) {}

protected:
    
// Implementation
    LPUNKNOWN GetInterfaceHook(const void *iid);
    
// IUnknown methods
    STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject);
    STDMETHOD_(ULONG, AddRef)();
    STDMETHOD_(ULONG, Release)();
}
;

LPUNKNOWN CMyOleControlSite::GetInterfaceHook(
const void *iid)
{
    
if (IsEqualIID((REFIID) (*(IID*)iid), IID_IDocHostUIHandler))
        
return (IDocHostUIHandler *this;
    
return NULL;
}


// IUnknown methods
STDMETHODIMP CMyOleControlSite::QueryInterface(REFIID riid, void **ppvObject)
{
    
return COleControlSite::ExternalQueryInterface(&riid, ppvObject);
}

STDMETHODIMP_(ULONG) CMyOleControlSite::AddRef()
{
    
return ExternalAddRef();
}


STDMETHODIMP_(ULONG) CMyOleControlSite::Release()
{
    
return ExternalRelease();
}
我要创建自己的ControlSite,而CreateControlSite是protect的,所以我的派生一下:
class CMyRichEditCtrl : public CRichEditCtrl
{
    friend 
class CTestCtrlInRichEditDlg;
    DECLARE_DYNAMIC(CMyRichEditCtrl)
public:
    CWnd m_wndCtrl;

    BOOL CreateControlSite(COleControlContainer
* pContainer, 
        COleControlSite
** ppSite, UINT /* nID */, REFCLSID /* clsid */);
}
;
实现之:
IMPLEMENT_DYNAMIC(CMyRichEditCtrl, CRichEditCtrl)

BOOL CMyRichEditCtrl::CreateControlSite(COleControlContainer
* pContainer, 
                                   COleControlSite
** ppSite, UINT /* nID */, REFCLSID /* clsid */)
{
    
if(ppSite == NULL)
    
{
        ASSERT(FALSE);
        
return FALSE;
    }


    CMyOleControlSite 
*pOleSite = 
        
new CMyOleControlSite(pContainer);

    
*ppSite = pOleSite;
    (
*ppSite)->m_pCtrlCont = pContainer;
    
return TRUE;
}

在对话框的OnInitDialog函数里面:
m_wndRichCtrl.InitControlContainer();

    COleControlSite
* pControlSite = NULL;
    m_wndRichCtrl.CreateControlSite(m_wndRichCtrl.GetControlContainer(), 
&pControlSite, 102, CLSID_NULL/*CLSID_WebBrowser*/);
    POINT pt 
= 2020 };
    SIZE sz 
= 300300 };
    pControlSite
->CreateControl(&m_wndRichCtrl.m_wndCtrl, CLSID_WebBrowser,
        _T(
"^_^"), WS_VISIBLE|WS_CHILD|WS_TABSTOP|WS_GROUP, &pt, &sz, 102);
    COleControlSiteOrWnd
* pSiteOrWnd = new COleControlSiteOrWnd(pControlSite);
    m_wndRichCtrl.GetControlContainer()
->m_listSitesOrWnds.AddTail(pSiteOrWnd);
    IWebBrowser2
* pIWebBrowser = NULL;
    pControlSite
->m_pInPlaceObject->QueryInterface(IID_IWebBrowser2, (void**)&pIWebBrowser);
    pIWebBrowser
->Navigate2(&CComVariant("www.cppblog.com/wlwlxj"), NULL, NULL, NULL, NULL);
    pIWebBrowser
->Release();
    IOleControl
* pIOleCtrl = NULL;
    pControlSite
->m_pInPlaceObject->QueryInterface(IID_IOleControl, (void**)&pIOleCtrl);
    pIOleCtrl
->Release();
这样就ok拉。上面反映了一个控件入住一个窗体的过程。

效果:



posted on 2007-07-07 00:59 万连文 阅读(2980) 评论(2)  编辑 收藏 引用 所属分类: MFC

FeedBack:
# re: 纯技术讨论com控件创建过程
2007-07-07 07:36 | SmartPtr
COM容器的使用, COleControlContainer和COleControlSite, 受教了。记得以前面试的时候被问到过COM容器,当时就说不出个所以然来  回复  更多评论
  
# re: 纯技术讨论com控件创建过程
2007-09-15 23:29 | testactivex
楼主的代码好像不行啊, 可以把完整的例子贴出来么?  回复  更多评论
  

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


简历下载
联系我

<2006年11月>
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

常用链接

留言簿(66)

随笔分类

随笔档案

相册

搜索

  •  

最新评论

阅读排行榜

评论排行榜