我想创建一个支持模式对话框和无模式对话框的ActiveX控件,它们可以同时在多个IE9〜IE11选项卡页面中使用。这意味着ActiveX控件在当前IE选项卡页面中弹出的对话框不会阻止我们切换到其他IE选项卡页面,并且这些对话框仅显示在当前IE选项卡页面中。首先,我通过Visual Studio 2010使用ATL / C ++创建了一个名为AtlActiveX的ATL动态链接库(DLL)应用程序。然后添加一个名为AtlActiveXCtl的ActiveX控件,并指定允许合并代理/存根代码和IObjectWithSite(IE对象支持)选项。然后添加一个名为IDD_DIALOG1的对话框资源。如果此处未提及,则其他选项保留为默认值。由于需要支持Windows /对话框,因此必须在CAtlActiveXCtl构造函数中分配成员变量m_bWindowOnly。之后,为WM_CREATE消息添加消息处理程序,在OnCreate函数中显示对话框。下面附有AtlActiveXCtl.h的完整代码。
我提到了关于StackOverflow的另一个问题Display Modal Dialog Box with ActiveX。在OnCreate()函数中测试了三个弹出对话框。
#pragma once
#include "resource.h"
#include <atlctl.h>
#include "AtlActiveX_i.h"
using namespace ATL;
// Modeless dialog
class CModelessDialog : public CDialogImpl<CModelessDialog>
{
public:
enum { IDD = IDD_DIALOG1 };
BEGIN_MSG_MAP(CModelessDialog)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
MESSAGE_HANDLER(WM_CLOSE, OnClose)
END_MSG_MAP()
LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL &)
{
return 0;
}
LRESULT OnClose(UINT, WPARAM, LPARAM, BOOL &)
{
DestroyWindow();
return 0;
}
};
// CAtlActiveXCtl
class ATL_NO_VTABLE CAtlActiveXCtl :
public CComObjectRootEx<CComSingleThreadModel>,
public IDispatchImpl<IAtlActiveXCtl, &IID_IAtlActiveXCtl, &LIBID_AtlActiveXLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
public IOleControlImpl<CAtlActiveXCtl>,
public IOleObjectImpl<CAtlActiveXCtl>,
public IOleInPlaceActiveObjectImpl<CAtlActiveXCtl>,
public IViewObjectExImpl<CAtlActiveXCtl>,
public IOleInPlaceObjectWindowlessImpl<CAtlActiveXCtl>,
public ISupportErrorInfo,
public IObjectWithSiteImpl<CAtlActiveXCtl>,
public IQuickActivateImpl<CAtlActiveXCtl>,
public IDataObjectImpl<CAtlActiveXCtl>,
public IProvideClassInfo2Impl<&CLSID_AtlActiveXCtl, NULL, &LIBID_AtlActiveXLib>,
public CComCoClass<CAtlActiveXCtl, &CLSID_AtlActiveXCtl>,
public CComControl<CAtlActiveXCtl>
{
public:
CAtlActiveXCtl()
{
m_bWindowOnly = 1;
}
DECLARE_OLEMISC_STATUS(OLEMISC_RECOMPOSEONRESIZE |
OLEMISC_CANTLINKINSIDE |
OLEMISC_INSIDEOUT |
OLEMISC_ACTIVATEWHENVISIBLE |
OLEMISC_SETCLIENTSITEFIRST
)
DECLARE_REGISTRY_RESOURCEID(IDR_ATLACTIVEXCTL)
BEGIN_COM_MAP(CAtlActiveXCtl)
COM_INTERFACE_ENTRY(IAtlActiveXCtl)
COM_INTERFACE_ENTRY(IDispatch)
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(ISupportErrorInfo)
COM_INTERFACE_ENTRY(IQuickActivate)
COM_INTERFACE_ENTRY(IDataObject)
COM_INTERFACE_ENTRY(IProvideClassInfo)
COM_INTERFACE_ENTRY(IProvideClassInfo2)
COM_INTERFACE_ENTRY(IObjectWithSite)
END_COM_MAP()
BEGIN_PROP_MAP(CAtlActiveXCtl)
PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)
PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)
// Example entries
// PROP_ENTRY_TYPE("Property Name", dispid, clsid, vtType)
// PROP_PAGE(CLSID_StockColorPage)
END_PROP_MAP()
BEGIN_MSG_MAP(CAtlActiveXCtl)
CHAIN_MSG_MAP(CComControl<CAtlActiveXCtl>)
DEFAULT_REFLECTION_HANDLER()
MESSAGE_HANDLER(WM_CREATE, OnCreate)
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* const arr[] =
{
&IID_IAtlActiveXCtl,
};
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(VIEWSTATUS_SOLIDBKGND | VIEWSTATUS_OPAQUE)
// IAtlActiveXCtl
public:
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
IOleInPlaceFrame *pOleInPlaceFrame = NULL;
IOleInPlaceUIWindow *pOleInPlaceUIwindow = NULL;
IOleInPlaceSite *pOleInPlaceSite = NULL;
OLEINPLACEFRAMEINFO oleInPlaceFrameInfo;
oleInPlaceFrameInfo.cb = sizeof(oleInPlaceFrameInfo);
HRESULT hr = m_spClientSite->QueryInterface(IID_IOleInPlaceSite, (LPVOID *)&pOleInPlaceSite);
if (hr != S_OK)
return S_OK;
RECT rc1, rc2;
hr = pOleInPlaceSite->GetWindowContext(&pOleInPlaceFrame, &pOleInPlaceUIwindow, &rc1, &rc2, &oleInPlaceFrameInfo);
{
HWND hWndTop = NULL;
pOleInPlaceSite->GetWindow(&hWndTop);
pOleInPlaceFrame->EnableModeless(TRUE);
::EnableWindow(hWndTop, FALSE);
//[1] Message box, cannot switch tab page
MessageBox(L"Hello, world!", L"MSG", MB_OK);
//[2] Modal dialog, cannot switch tab page
CSimpleDialog<IDD_DIALOG1> dlg;
dlg.DoModal(hWndTop);
//[3] Modeless dialog, can switch tab page, but always stays on top of IE browser
CModelessDialog *pDlg = new CModelessDialog;
pDlg->Create(hWndTop);
pDlg->ShowWindow(SW_SHOWNORMAL);
pOleInPlaceFrame->EnableModeless(FALSE);
::EnableWindow(hWndTop, TRUE);
}
return 0;
}
HRESULT OnDraw(ATL_DRAWINFO& di)
{
RECT& rc = *(RECT*)di.prcBounds;
// Set Clip region to the rectangle specified by di.prcBounds
HRGN hRgnOld = NULL;
if (GetClipRgn(di.hdcDraw, hRgnOld) != 1)
hRgnOld = NULL;
bool bSelectOldRgn = false;
HRGN hRgnNew = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
if (hRgnNew != NULL)
bSelectOldRgn = (SelectClipRgn(di.hdcDraw, hRgnNew) != ERROR);
Rectangle(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom);
SetTextAlign(di.hdcDraw, TA_CENTER|TA_BASELINE);
LPCTSTR pszText = _T("AtlActiveXCtl");
TextOut(di.hdcDraw,
(rc.left + rc.right) / 2,
(rc.top + rc.bottom) / 2,
pszText,
lstrlen(pszText));
if (bSelectOldRgn)
SelectClipRgn(di.hdcDraw, hRgnOld);
return S_OK;
}
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
};
OBJECT_ENTRY_AUTO(__uuidof(AtlActiveXCtl), CAtlActiveXCtl)
与普通的Win32 GUI应用程序一样,IE11选项卡页内的ActiveX控件需要支持模式对话框和无模式对话框。谁能帮助我解决这个问题?