最近一直都在研究关于有界面的组件如何做为主框架的子view显示出来, 终于有一些心得,在此把它贴出来供高人指点.并分享成果,难免有错误之处,因为我的水平只有这么多.
任何组件都会存在唯一的CLSID,此组件也一样存在这个ID,在工程目录下面找到和类名相同的HTM文件,运行它就是发现就是组件的界面,功能也是组件里写的功能.HTML文件里是可以写脚本的,所以也可以把组件的事件同时抛出来,就可以使用WebBrowser2封装的容器显示此页面.由于组件在系统里也会以HTML页面的形式呈现出来,并在WebBrowser2里显示,其实也就没有必要使用ATL做界面了,只需要使用HTML+脚本写出一个界面,使用此容器就可以在VC的框架里正确的运行,从而实现VC和脚本的相互调用.(有关脚本和VC的相互调用参考其它文档)
容器的代码如下:
IDL
import "oaidl.idl";
import "ocidl.idl";
import "atliface.idl";
#include "olectl.h"

[
object,
uuid(0BB8B6DB-52F9-4C2A-BB04-5150B8FE5841),
dual,
helpstring("IATLOpener Interface"),
pointer_default(unique)
]
interface IATLOpener : IDispatch // 对外的接口

...{
[id(1), helpstring("method OpenURL")] HRESULT OpenURL(BSTR bstrURL);
[id(2), helpstring("method OpenHTML")] HRESULT OpenHTML(BSTR bstrURL);
};

[
object, dual,
uuid(8F1C3679-9EED-419A-9D42-C1B7C60E2F5B),
helpstring("IATLOpenerUI Interface"),
pointer_default(unique)
]
interface IATLOpenerUI : IDocHostUIHandlerDispatch // 容器有滚动条,对脚本的接口

...{
// Example method that will be called by the HTML
[id(1), helpstring("method OnClick")] HRESULT OnClick([in]IDispatch* pdispBody, [in]VARIANT varColor);
[id(2), helpstring("method fireEvent")] HRESULT fireEvent(BSTR bstrID, BSTR bstrValue);
};

[
uuid(370F70AC-6AAA-41E9-980F-14431FECBDB1),
version(1.0),
helpstring("ATLMaskWrapper 1.0 Type Library")
]
library ATLMASKWRAPPERLib

...{
importlib("stdole32.tlb");
importlib("stdole2.tlb");

[
uuid(0E0D5320-125B-4078-B002-544CC536CEF5),
helpstring("_IATLOpenerEvents Interface")
]
dispinterface _IATLOpenerEvents

...{
properties:
methods:
[id(1), helpstring("method OnEvent")] HRESULT OnEvent(BSTR bstrID,BSTR bstrValue);
[id(2), helpstring("method OnEvent2")] HRESULT OnEvent2(BSTR bstrID,BSTR bstrValue1,BSTR bstrValue2);
[id(3), helpstring("method OnEvent3")] HRESULT OnEvent3(BSTR bstrID,BSTR bstrValue1,BSTR bstrValue2,BSTR bstrValue3);
[id(4), helpstring("method OnSetFrameTitle")] HRESULT OnSetFrameTitle(BSTR bstrFrameTitle);
};

[
uuid(4B9529DA-1FE1-49AC-AD51-9EAA66C97351),
helpstring("ATLOpener Class")
]
coclass ATLOpener

...{
[default] interface IATLOpener;
[default, source] dispinterface _IATLOpenerEvents;
interface IATLOpenerUI;
};
};

头文件
#ifndef __ATLOPENER_H_
#define __ATLOPENER_H_

#include "resource.h" // main symbols
#include <atlctl.h>
#include <MSHTMCID.H>
#include <MSHTMHST.h>
#include "ATLMaskWrapperCP.h"



/**//////////////////////////////////////////////////////////////////////////////
// CATLOpener
class ATL_NO_VTABLE CATLOpener :
public CComObjectRootEx<CComSingleThreadModel>,
public IDispatchImpl<IATLOpener, &IID_IATLOpener, &LIBID_ATLMASKWRAPPERLib>,
public IDispatchImpl<IATLOpenerUI, &IID_IATLOpenerUI, &LIBID_ATLMASKWRAPPERLib>,
public CComControl<CATLOpener>,
public IPersistStreamInitImpl<CATLOpener>,
public IOleControlImpl<CATLOpener>,
public IOleObjectImpl<CATLOpener>,
public IOleInPlaceActiveObjectImpl<CATLOpener>,
public IViewObjectExImpl<CATLOpener>,
public IOleInPlaceObjectWindowlessImpl<CATLOpener>,
public ISupportErrorInfo,
public IConnectionPointContainerImpl<CATLOpener>,
public CComCoClass<CATLOpener, &CLSID_ATLOpener>,
public IProvideClassInfo2Impl<&CLSID_ATLOpener, &DIID__IATLOpenerEvents, &LIBID_ATLMASKWRAPPERLib>,
public CProxy_IATLOpenerEvents< CATLOpener >,
public IObjectSafetyImpl<CATLOpener, INTERFACESAFE_FOR_UNTRUSTED_CALLER>

...{
public:
CATLOpener()

...{
m_bWindowOnly = TRUE;
HRESULT hr =CoInitialize(NULL);
}
~CATLOpener()

...{
CoUninitialize();
}

BEGIN_CATEGORY_MAP(CATLOpener)
IMPLEMENTED_CATEGORY(CATID_SafeForScripting)
IMPLEMENTED_CATEGORY(CATID_SafeForInitializing)
END_CATEGORY_MAP()

DECLARE_REGISTRY_RESOURCEID(IDR_ATLOPENER)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CATLOpener)
COM_INTERFACE_ENTRY(IATLOpener)
COM_INTERFACE_ENTRY(IATLOpenerUI)
COM_INTERFACE_ENTRY2(IDispatch, IATLOpener)
COM_INTERFACE_ENTRY(IViewObjectEx)
COM_INTERFACE_ENTRY(IViewObject2)
COM_INTERFACE_ENTRY(IViewObject)
COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless)
COM_INTERFACE_ENTRY(IOleInPlaceObject)
COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless)
COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)
COM_INTERFACE_ENTRY(IOleControl)
COM_INTERFACE_ENTRY(IOleObject)
COM_INTERFACE_ENTRY(IPersistStreamInit)
COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit)
COM_INTERFACE_ENTRY(ISupportErrorInfo)
COM_INTERFACE_ENTRY(IConnectionPointContainer)
COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)
COM_INTERFACE_ENTRY(IProvideClassInfo)
COM_INTERFACE_ENTRY(IProvideClassInfo2)
COM_INTERFACE_ENTRY(IObjectSafety)
END_COM_MAP()

BEGIN_PROP_MAP(CATLOpener)
PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)
PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)
// Example entries
// PROP_ENTRY("Property Description", dispid, clsid)
// PROP_PAGE(CLSID_StockColorPage)
END_PROP_MAP()

BEGIN_CONNECTION_POINT_MAP(CATLOpener)
CONNECTION_POINT_ENTRY(DIID__IATLOpenerEvents)
END_CONNECTION_POINT_MAP()

BEGIN_MSG_MAP(CATLOpener)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
CHAIN_MSG_MAP(CComControl<CATLOpener>)
END_MSG_MAP()
// Handler prototypes:
// LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
// LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
// LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);



// ISupportsErrorInfo
STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid)

...{
static const IID* arr[] =

...{
&IID_IATLOpener,
};
for (int i=0; i<sizeof(arr)/sizeof(arr[0]); i++)

...{
if (InlineIsEqualGUID(*arr[i], riid))
return S_OK;
}
return S_FALSE;
}

// IViewObjectEx
DECLARE_VIEW_STATUS(0)

// IDispatch 一定要重载,否则脚本找不到接口
public:
STDMETHOD (GetIDsOfNames) (REFIID riid,
LPOLESTR* rgszNames,
UINT cNames,
LCID lcid,
DISPID* rgdispid);
STDMETHOD (Invoke) (DISPID dispidMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS* pdispparams,
VARIANT* pvarResult,
EXCEPINFO* pexcepinfo,
UINT* puArgErr);

// IATLOpener
public:
STDMETHOD(OpenURL)(BSTR bstrURL);

// IATLOpenerUI
public:
// Example method called by the HTML to change the <BODY> background color
STDMETHOD(OnClick)(IDispatch* pdispBody, VARIANT varColor);

public:

LRESULT OnCreate(UINT /**//*uMsg*/, WPARAM /**//*wParam*/, LPARAM /**//*lParam*/, BOOL& /**//*bHandled*/);

public:
STDMETHOD(fireEvent)(BSTR bstrID, BSTR bstrValue);
CComPtr<IWebBrowser2> m_spBrowser;

// IDocHostUIHandlerDispatch
public:
STDMETHOD(OpenHTML)(BSTR bstrURL);
STDMETHOD (ShowContextMenu) (

/**//* [in] */ DWORD dwID,

/**//* [in] */ DWORD x,

/**//* [in] */ DWORD y,

/**//* [in] */ IUnknown *pcmdTarget,

/**//* [in] */ IDispatch *pdispReserved,

/**//* [retval][out] */ HRESULT *dwRetVal)

...{
#define IDR_BROWSE_CONTEXT_MENU 24641
#define IDM_REFRESH2 6042
#define IDM_SAVEASDESKTOPITEM 2278
#define IDM_SEPARATOR 0
#define IDM_SEPARATOR2 6047
HRESULT hr;
HINSTANCE hinstSHDOCLC;
HWND hwnd;
HMENU hMenuParent, hMenu;
CComPtr<IOleCommandTarget> spCT;
CComPtr<IOleWindow> spWnd;

MENUITEMINFO mii = ...{0};
CComVariant var, var1, var2;
hr = pcmdTarget->QueryInterface(IID_IOleCommandTarget, reinterpret_cast< void ** > (&spCT));
hr = spCT->QueryInterface(IID_IOleWindow, reinterpret_cast< void ** > (&spWnd));
hr = spWnd->GetWindow(&hwnd);
hinstSHDOCLC = LoadLibrary(TEXT("SHDOCLC.DLL"));
if (hinstSHDOCLC == NULL)

...{
// Error loading module -- fail as securely as possible
return S_FALSE;
}
hMenuParent = LoadMenu(hinstSHDOCLC,
MAKEINTRESOURCE(IDR_BROWSE_CONTEXT_MENU));
if (dwID == 5) //anchor
hMenu = GetSubMenu(hMenuParent, static_cast< int > (0));
else
hMenu = GetSubMenu(hMenuParent, static_cast< int > (dwID));
// Remove View Source
DeleteMenu(hMenu, IDM_REGISTRYREFRESH, MF_BYCOMMAND);
DeleteMenu(hMenu, IDM_REFRESH, MF_BYCOMMAND);
DeleteMenu(hMenu, IDM_REFRESH2, MF_BYCOMMAND);
DeleteMenu(hMenu, IDM_PROPERTIES, MF_BYCOMMAND);
DeleteMenu(hMenu, IDM_ADDFAVORITES, MF_BYCOMMAND);
DeleteMenu(hMenu, IDM_CREATESHORTCUT, MF_BYCOMMAND);
DeleteMenu(hMenu, IDM_VIEWSOURCE, MF_BYCOMMAND);
DeleteMenu(hMenu, IDM_LANGUAGE, MF_BYCOMMAND);
DeleteMenu(hMenu, IDM_GOBACKWARD, MF_BYCOMMAND);
DeleteMenu(hMenu, IDM_GOFORWARD, MF_BYCOMMAND);
DeleteMenu(hMenu, IDM_SAVEBACKGROUND, MF_BYCOMMAND);
DeleteMenu(hMenu, IDM_SETWALLPAPER, MF_BYCOMMAND);
DeleteMenu(hMenu, IDM_COPYBACKGROUND, MF_BYCOMMAND);
DeleteMenu(hMenu, IDM_SAVEASDESKTOPITEM, MF_BYCOMMAND);
DeleteMenu(hMenu, IDM_PRINT, MF_BYCOMMAND);
int iItemCount = GetMenuItemCount(hMenu)-1;
for(int i=iItemCount; i>=0; i--)

...{
if(GetMenuItemID(hMenu,i) == IDM_SEPARATOR || GetMenuItemID(hMenu,i) == IDM_SEPARATOR2)

...{
if(i==0)
DeleteMenu(hMenu, i, MF_BYPOSITION);
else if(GetMenuItemID(hMenu,i-1) == IDM_SEPARATOR || GetMenuItemID(hMenu,i-1) == IDM_SEPARATOR2)
DeleteMenu(hMenu, i, MF_BYPOSITION);
}
}
iItemCount = GetMenuItemCount(hMenu)-1;
if(GetMenuItemID(hMenu,iItemCount) == IDM_SEPARATOR || GetMenuItemID(hMenu,iItemCount) == IDM_SEPARATOR2)
DeleteMenu(hMenu, iItemCount, MF_BYPOSITION);
// Show shortcut menu
int iSelection = ::TrackPopupMenu(hMenu,
TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD | TPM_RIGHTBUTTON,
x,
y,
0,
hwnd,
(RECT*)NULL);
// Send selected shortcut menu item command to shell
LRESULT lr = ::SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(LOWORD(iSelection), 0x0), 0);
::DestroyMenu( hMenuParent );
FreeLibrary(hinstSHDOCLC);
if (iSelection != 31) //if not select all

...{
SetFocus();
}
//--------
*dwRetVal = S_OK;
return S_OK;
}

STDMETHOD (GetHostInfo) (

/**//* [out][in] */ DWORD *pdwFlags,

/**//* [out][in] */ DWORD *pdwDoubleClick)

...{
return E_NOTIMPL;
}


STDMETHOD (ShowUI) (

/**//* [in] */ DWORD dwID,

/**//* [in] */ IUnknown *pActiveObject,

/**//* [in] */ IUnknown *pCommandTarget,

/**//* [in] */ IUnknown *pFrame,

/**//* [in] */ IUnknown *pDoc,

/**//* [retval][out] */ HRESULT *dwRetVal)

...{
return E_NOTIMPL;
}


STDMETHOD (HideUI) (void)

...{
return E_NOTIMPL;
}


STDMETHOD (UpdateUI) (void)

...{
return E_NOTIMPL;
}

STDMETHOD (EnableModeless) (

/**//* [in] */ VARIANT_BOOL fEnable)

...{
return E_NOTIMPL;
}


STDMETHOD (OnDocWindowActivate) (

/**//* [in] */ VARIANT_BOOL fActivate)

...{
return E_NOTIMPL;
}


STDMETHOD (OnFrameWindowActivate) (

/**//* [in] */ VARIANT_BOOL fActivate)

...{
return E_NOTIMPL;
}


STDMETHOD (ResizeBorder) (

/**//* [in] */ long left,

/**//* [in] */ long top,

/**//* [in] */ long right,

/**//* [in] */ long bottom,

/**//* [in] */ IUnknown *pUIWindow,

/**//* [in] */ VARIANT_BOOL fFrameWindow)

...{
return E_NOTIMPL;
}


STDMETHOD (TranslateAccelerator) (

/**//* [in] */ DWORD hWnd,

/**//* [in] */ DWORD nMessage,

/**//* [in] */ DWORD wParam,

/**//* [in] */ DWORD lParam,

/**//* [in] */ BSTR bstrGuidCmdGroup,

/**//* [in] */ DWORD nCmdID,

/**//* [retval][out] */ HRESULT *dwRetVal)

...{
return E_NOTIMPL;
}


STDMETHOD (GetOptionKeyPath) (

/**//* [out] */ BSTR *pbstrKey,

/**//* [in] */ DWORD dw)

...{
return E_NOTIMPL;
}


STDMETHOD (GetDropTarget) (

/**//* [in] */ IUnknown *pDropTarget,

/**//* [out] */ IUnknown **ppDropTarget)

...{
return E_NOTIMPL;
}


STDMETHOD (GetExternal) (

/**//* [out] */ IDispatch **ppDispatch)

...{
//return E_NOTIMPL;
return QueryInterface(IID_IATLOpenerUI,(void**)ppDispatch);
}


STDMETHOD (TranslateUrl) (

/**//* [in] */ DWORD dwTranslate,

/**//* [in] */ BSTR bstrURLIn,

/**//* [out] */ BSTR *pbstrURLOut)

...{
return E_NOTIMPL;
}


STDMETHOD (FilterDataObject) (

/**//* [in] */ IUnknown *pDO,

/**//* [out] */ IUnknown **ppDORet)

...{
return E_NOTIMPL;
}
};

#endif //__ATLOPENER_H_

CPP文件
#include "stdafx.h"
#include "ATLMaskWrapper.h"
#include "ATLOpener.h"
#include "PrepareHtml.h"

typedef IDispatchImpl<IATLOpener, &IID_IATLOpener, &LIBID_ATLMASKWRAPPERLib> ATLOpenerType;
typedef IDispatchImpl<IATLOpenerUI, &IID_IATLOpenerUI, &LIBID_ATLMASKWRAPPERLib> ATLOpenerUIType;
const DISPID INTERFACEMASK = 0xFFFF0000;
const DISPID DISPIDMASK = 0x0000FFFF;
const DISPID IDISPATLOPENER = 0x00010000;
const DISPID IDISPATLOPENERUI = 0x00020000;


/**//////////////////////////////////////////////////////////////////////////////
// CATLOpener
STDMETHODIMP CATLOpener::GetIDsOfNames(REFIID riid,
LPOLESTR* rgszNames,
UINT cNames,
LCID lcid,
DISPID* rgdispid)

...{
HRESULT hr = DISP_E_UNKNOWNNAME;

hr = ATLOpenerType::GetIDsOfNames(riid,
rgszNames, cNames, lcid, rgdispid);
if (SUCCEEDED(hr))

...{
rgdispid[0] |= IDISPATLOPENER;
return hr;
}

hr = ATLOpenerUIType::GetIDsOfNames(riid,
rgszNames,
cNames,
lcid,
rgdispid);
if (SUCCEEDED(hr))

...{
rgdispid[0] |= IDISPATLOPENERUI;
return hr;
}

return hr;
}

STDMETHODIMP CATLOpener::Invoke(DISPID dispidMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS* pdispparams,
VARIANT* pvarResult,
EXCEPINFO* pexcepinfo,
UINT* puArgErr)

...{
DWORD dwInterface = (dispidMember & INTERFACEMASK);
dispidMember &= DISPIDMASK;

switch(dwInterface)

...{

case IDISPATLOPENERUI:
return ATLOpenerUIType::Invoke(dispidMember,
riid,
lcid,
wFlags,
pdispparams,
pvarResult,
pexcepinfo,
puArgErr);

case IDISPATLOPENER:
default:
//return DISP_E_MEMBERNOTFOUND;
return ATLOpenerType::Invoke(dispidMember,
riid,
lcid,
wFlags,
pdispparams,
pvarResult,
pexcepinfo,
puArgErr);
}

}

STDMETHODIMP CATLOpener::OnClick(IDispatch* pdispBody, VARIANT varColor)

...{
CComQIPtr<IHTMLBodyElement> spBody(pdispBody);
if (spBody != NULL)
spBody->put_bgColor(varColor);
return S_OK;
}


LRESULT CATLOpener::OnCreate(UINT /**//*uMsg*/, WPARAM /**//*wParam*/, LPARAM /**//*lParam*/, BOOL& /**//*bHandled*/)

...{
CAxWindow wnd(m_hWnd);
HRESULT hr = wnd.CreateControl(IDH_ATLOPENER);
if (SUCCEEDED(hr))

...{
// 有滚动条
CComQIPtr<IDocHostUIHandlerDispatch> pIUI(static_cast<IDocHostUIHandlerDispatch*>(this));
hr = wnd.SetExternalUIHandler(pIUI);
// 无滚动条
// hr = wnd.SetExternalDispatch(static_cast<IATLOpenerUI*>(this));
}

if (SUCCEEDED(hr))

...{
hr = wnd.QueryControl(IID_IWebBrowser2, (void**)&m_spBrowser);
}
return SUCCEEDED(hr) ? 0 : -1;
}

STDMETHODIMP CATLOpener::OpenURL(BSTR bstrURL) // 显示组件界面

...{
// TODO: Add your implementation code here
HRESULT hr = NULL;

hr = m_spBrowser->Navigate(bstrURL, NULL, NULL, NULL, NULL);

if (hr != S_OK)

...{
MessageBox("Navigate failed!");
}

return S_OK;
}

STDMETHODIMP CATLOpener::fireEvent(BSTR bstrID, BSTR bstrValue) // 脚本抛事件

...{
// TODO: Add your implementation code here
Fire_OnEvent(bstrID,bstrValue);
return S_OK;
}

STDMETHODIMP CATLOpener::OpenHTML(BSTR bstrURL) // 显示HTML页面

...{
// TODO: Add your implementation code here
CPrepareHtml Prepare;
Prepare.Prepare(bstrURL);

return S_OK;
}
