程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> 匯編語言 >> Win32編程點滴 - 簡單ActiveX控件的使用

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;
  }
  ....
}

下載源代碼:files.cnblogs.com/Greatest/TestActiveX1.zip

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved