2013-08-20 59 views
3

ATL用於COM ActiveX託管的標準類CAxHostWindow不支持接口IDocHostUIHandler2。我如何擴展IDocHostUIHandler2支持的CAxHostWindow類?如何擴展CAxHostWindow?

回答

1

CAxHostWindow類在源代碼中可用。所以,你可以:

  1. 編輯或重複類,並添加界面右邊有
  2. 您可以通過聚合的COM aggregation類到你自己的,這增加了支持IDocHostUIHandler2 - 在這種情況下,你不需要源編輯,但源代碼仍然是一個很好的引導你的途徑;或者你甚至可以從它繼承。

#2解決方案在不觸及ATL代碼本身方面更爲乾淨,但您也必須解決實例化問題。該類不是COM可創建的,它是通過ATL創建者類創建的。你也必須照顧這個,例如通過爲AtlAxAttachControl函數提供備用選項。

+0

不幸的是,IE10包含一個錯誤。在打印或預覽HTML文本時,它不考慮從GetOptionKeyPath()和GetOverrideKeyPath()(接口IDocHostUIHandler/IDocHostUIHandler2)中收集的數據。但是,這是另一回事。 – 23W

+0

@ 23W,有一個更好的方式來處理MSHTML的打印設置。我相信你會在這裏找到它:) – Noseratio

2

實際上,有一種方法可以在不修改它的情況下自定義CAxHostWindow。例如,我想在客戶站點對象上實現IOleCommandTarget。棘手的部分是重寫創建主機窗口。下面是它如何做到:

class ATL_NO_VTABLE CWebBrowserHost : 
    public CAxHostWindow, 
    public IOleCommandTarget 
{ 
public: 
    static CWndClassInfo& GetWndClassInfo() 
    { 
    static CWndClassInfo wc = 
    { 
     { sizeof(WNDCLASSEX), 0, StartWindowProc, 
     0, 0, 0, 0, 0, (HBRUSH)(COLOR_WINDOW + 1), 0, NULL, 0 }, 
     NULL, NULL, IDC_ARROW, TRUE, 0, _T("") 
    }; 
    return wc; 
    } 

    DECLARE_PROTECT_FINAL_CONSTRUCT() 

    DECLARE_NO_REGISTRY() 
    DECLARE_POLY_AGGREGATABLE(CWebBrowserHost) 
    DECLARE_GET_CONTROLLING_UNKNOWN() 

    BEGIN_COM_MAP(CWebBrowserHost) 
    COM_INTERFACE_ENTRY(IDocHostUIHandler) 
    COM_INTERFACE_ENTRY(IOleCommandTarget) 
    COM_INTERFACE_ENTRY_CHAIN(CAxHostWindow) 
    END_COM_MAP() 

    HWND Create(
    _In_opt_ HWND hWndParent, 
    _In_ _U_RECT rect = NULL, 
    _In_opt_z_ LPCTSTR szWindowName = NULL, 
    _In_ DWORD dwStyle = 0, 
    _In_ DWORD dwExStyle = 0, 
    _In_ _U_MENUorID MenuOrID = 0U, 
    _In_opt_ LPVOID lpCreateParam = NULL) 
    { 
    ATOM atom = GetWndClassInfo().Register(&m_pfnSuperWindowProc); 
    if (!atom) 
     return NULL; 

    // Allocate the thunk structure here, where we can fail gracefully. 
    BOOL result = m_thunk.Init(NULL,NULL); 
    if (result == FALSE) 
    { 
     SetLastError(ERROR_OUTOFMEMORY); 
     return NULL; 
    } 

    _AtlWinModule.AddCreateWndData(&m_thunk.cd, this); 

    dwStyle = GetWndStyle(dwStyle); 
    dwExStyle = GetWndExStyle(dwExStyle); 

    // set caption 
    if (szWindowName == NULL) 
     szWindowName = GetWndCaption(); 

    return CWindow::Create((LPCTSTR)atom, hWndParent, rect, szWindowName, dwStyle, dwExStyle, MenuOrID, lpCreateParam); 
    } 

    // IOleCommandTarget methods 
    // ... 

} 

下面是如何使用它:

CComPtr<CWebBrowserHost> m_webBrowserHost; 

//... 

// Create a child AX host window. 
CComObject<CWebBrowserHost>* pHost = NULL; 
hr = CComObject<CWebBrowserHost>::CreateInstance(&pHost); 
if (FAILED(hr)) 
    return 0; 
m_webBrowserHost = pHost; 

RECT rect; 
GetClientRect(&rect); 
m_webBrowserHost->Create(m_hWnd, rect, NULL, WS_CHILD | WS_VISIBLE); 
if (m_webBrowserHost->m_hWnd == NULL) 
    return 0; 

// Create WebBrowser control 
CComPtr<IUnknown> spControl; 
hr = pHost->CreateControlEx(
    OLESTR("{8856F961-340A-11D0-A96B-00C04FD705A2}"), // WebBrowser Control CLSID 
    m_webBrowserHost->m_hWnd, 
    NULL, 
    &spControl, 
    DIID_DWebBrowserEvents2, 
    ((IUnknown*)(IDispEventImpl<1, CMainWindow, &DIID_DWebBrowserEvents2, &LIBID_SHDocVw, 0xFFFF, 0xFFFF>*)this) 
); 

if (FAILED(hr)) 
    return 0; 
+1

謝謝你,我做了幾乎相同的代碼。我不喜歡聚合方法。 – 23W

+0

沒問題。您現在可以自由地覆蓋由'CAxHostWindow'實現的站點對象的任何方法/接口,包括'IDocHostUIHandler',或者添加新的。我也不喜歡聚集,它不允許使用'CreateControlEx'等。 – Noseratio