[转]Win32编程系列之ActiveX控件的使用

  • 虽然这里一片的.net气氛,到处充斥着像MVC、WPF、WorkFlow、LINQ等各种niubility的术语。但我们使用的Windows还是由COM技术主宰着;我们在选择日常使用的软件时,也会避免使用.net开发的软件。即便是.net的桌面程序,也会经常使用ActiveX控件。这篇文章就让我们用最原始的方式来使用ActiveX,不使用任何MFC,ATL等框架,也不使用编译器提供的#import之类的指令,也不使用任何ide提供的向导。

    像OLE、ActiveX等COM的术语,即便是微软也说不清它们的关系,所以下面说的我也这样模棱两可下去,只要明白意思即可。

    首先,要了解一下的是ActiveX技术是为了做“嵌 入”这样的功能而诞生的,比如:在Word中插入一张Bitmap图片,双击此图片,Word会调用画笔程序的功能来编辑图片,整个Word的菜单栏也会变成画笔程序的菜单栏。所以,ActiveX控件相当的复杂,有着几十个相关的接口。简单的说来,ActiveX控件的父窗口被称为“容器”,所以作为 ActiveX控件的使用者来说,要实现的接口基本上都是IOleXXXXContainer或IOleXXXXSite之类的;而 ActiveX则实现了IOleXXXXObject等接口。在这些接口中,大多有“InPlace”这个术语,指 的是“InPlace edit”,也就是Word通过双击图片调用画笔编辑图片就称为“InPlace edit”(仅仅了解一下,和这篇文章说的使用AcitveX控件无关)。

    在这样一篇文章中,我并不想讲很多COM或者AcitveX的知识,只是讲使用ActiveX所必须涉及的接口,然后你就可以去查MSDN中 的其他一些可选的接口来一步步对这个ActiveX加强控制。

    作为一个最简单的程序,我们需要实现的接口有:IOleClientSite和IOleInPlaceSite。使用到的AcitveX提供的接口有:IOleObject和 IOleInPlaceObject。创建ActiveX控件的步骤:

    创建一个类,实现IOleClientSite和IOleInPlaceSite。

    使用CoCreateInstance创建相应 ActiveX控件的实例,并获取它的IOleObject接口指针。

    调用IOleObject::SetClientSite传入第 一步中的类的指针。

    调用IOleObject::DoVerb完成ActiveX控件的创建。

    之后,可以调用 ActiveX控件的IOleInPlaceObject::SetObjectRects调整控件的大小和位置。

    根据以上步骤,创 建如下函数:

    HRESULT CreateAxControl(HWND hWnd,const wchar_t *  ProgId,IUnknown ** ppControlUnknown,IUnknown ** ppContainerUnknown);

    第一 个参数hWnd是父窗口句柄。ProgId是ActiveX控件的ProgId,因为我们不使用编译器的#import,一般不 知道所要创建控件的CLSID。ppControlUnknown是用来返回ActiveX控件的IUnknown指针。 ppContainerUnknown是用来返回用来代表父窗口的IUnknown指针。

    代码如下(这里的代码去除了 出错的处理):

    HRESULT CreateAxControl(HWND hWnd,const wchar_t *  ProgId,IUnknown ** ppControlUnknown,IUnknown ** ppContainerUnknown)
    {
       HRESULT hr;
      CLSID cls;
      IOleObject * pObject = NULL;
       CControlContainer * pContainer = NULL;
      //通过ProgId得到CLSID 
       CLSIDFromProgID(ProgId,&cls);
    
      //创建ActiveX控件的对象,顺便得到 IOleObject指针
      CoCreateInstance (cls,NULL,CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER|CLSCTX_LOCAL_SERVER,
         IID_IOleObject,(void**)&pObject);
    
      //CControlContainer是实现了 IOleClientSite和IOleInPlaceSite接口的类 
      pContainer = new CControlContainer (hWnd);
    
      //调用IOleObject::SetClientSite,传入容器指针
      pObject- >SetClientSite(pContainer);
    
      //调用IOleObject::DoVerb,显示控件
       pObject->DoVerb(OLEIVERB_SHOW,0,pContainer,0,hWnd,0);
    
      //一些返回的参数
      pObject->QueryInterface(IID_IUnknown,(void**)ppControlUnknown);
       pContainer->QueryInterface(IID_IUnknown,(void**)ppContainerUnknown);
    
      if  (pObject) pObject->Release();
      if (pContainer) pContainer->Release();
      return S_OK;
    
  • CControlContainer类的实现非常简单,基本上IOleClientSite和IOleInPlaceSite接口大部分的方法 都只要简单的返回S_OK或E_NOTIMPLE即可。唯一需要实现的是IUnknown的方法,还有IOleWindow接口 (IOleInPlaceSite继承于IOleWindow)的GetWindow(返回父窗口的句柄)。代码如下:

    class CControlContainer:public IOleClientSite,public IOleInPlaceSite
    {
      HWND m_hWnd;
      ULONG m_refCnt;
    public:
      CControlContainer (HWND hWnd)
      {
        m_hWnd = hWnd;
        m_refCnt = 1;
       }
      ~CControlContainer()
      {
      }
      .... IUnknown的实现
      //IOleControlSite 
      STDMETHOD(SaveObject())
      {
        return  E_NOTIMPL;
      }
      STDMETHOD(GetMoniker(DWORD,DWORD,IMoniker**))
      {
        return E_NOTIMPL;
      }
      STDMETHOD(GetContainer(IOleContainer  **ppContainer))
      {
        return E_NOINTERFACE;
      }
       STDMETHOD(ShowObject())
      {
        return S_OK;
      }
       STDMETHOD(OnShowWindow(BOOL bShow))
      {
        return S_OK;
      }
      STDMETHOD(RequestNewObjectLayout())
      {
        return E_NOTIMPL;
       }
      //IOleWindow
      STDMETHOD(GetWindow(HWND * pHwnd))
      {
         *pHwnd = m_hWnd;
        return S_OK;
      }
      STDMETHOD (ContextSensitiveHelp(BOOL bEnterMode))
      {
        return S_OK;
      } 
      //IOleInPlaceSite 
      STDMETHOD(CanInPlaceActivate())
      {
         return S_OK;
      }
      STDMETHOD(OnInPlaceActivate())
      {
         return S_OK;
      }
      STDMETHOD(OnUIActivate())
      {
         return S_OK;
      }
      STDMETHOD(GetWindowContext(/* [out] */  IOleInPlaceFrame **ppFrame,
        /* [out] */ IOleInPlaceUIWindow **ppDoc,
        /* [out] */ LPRECT lprcPosRect,
        /* [out] */ LPRECT  lprcClipRect,
        /* [out][in] */ LPOLEINPLACEFRAMEINFO lpFrameInfo))
       {
        return E_NOTIMPL;
      }
      STDMETHOD(Scroll(SIZE  scrollSize))
      {
        return S_OK;
      }
      STDMETHOD (OnUIDeactivate(BOOL bUndoable))
      {
        return S_OK;
      }
       STDMETHOD(OnInPlaceDeactivate())
      {
        return S_OK;
      }
       STDMETHOD(DiscardUndoState())
      {
        return S_OK;
      }
       STDMETHOD(DeactivateAndUndo())
      {
        return S_OK;
      }
       STDMETHOD(OnPosRectChange(LPCRECT lprcPosRect))
      {
        return S_OK;
      }
    };

    • 接下来,在父窗口的窗口过程中,调用上面实现的函数,创建一个Flash控件:

      IUnknown * g_pControl = NULL;//控件的指针
      LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
      {
        ....
         switch(message)
        {
        case WM_CREATE:
          //Flash控件
           hr = CreateAxControl (hWnd,L"ShockwaveFlash.ShockwaveFlash",&pControl,&pContainer);
           if (SUCCESSED(hr))
          {
            VARIANT src;
             src.vt = VT_BSTR;
            src.bstrVal = SysAllocString (L"http://www.google.com/intl/en_ALL/images/logo.gif");
             DispSetProperty(pControl,L"movie",&src);//这个函数的实现,请下载源代码
          }
          break;
        case WM_SIZE:
          {
            //调 整控件的大小
            RECT rcClient;
            GetClientRect (hWnd,&rcClient);
            IOleInPlaceObject * pInPlaceObject;
             if (g_pControl &&
              SUCCEEDED(g_pControl- >QueryInterface(IID_IOleInPlaceObject,(void**)&pInPlaceObject)))
             {
              pInPlaceObject->SetObjectRects(&rcClient,&rcClient);
              pInPlaceObject->Release();
            }
          }
           break;
        }
        ....
      }


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值