在ActiveX控件中支持模式对话框和无模式对话框

时间:2019-05-17 13:51:35

标签: c++ internet-explorer activex ole

我想创建一个支持模式对话框和无模式对话框的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控件需要支持模式对话框和无模式对话框。谁能帮助我解决这个问题?

0 个答案:

没有答案