Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/134.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用自定义IDocHostUIHandler并关闭窗口时崩溃_C++_Webbrowser Control_C++builder_Mshtml_Twebbrowser - Fatal编程技术网

C++ 使用自定义IDocHostUIHandler并关闭窗口时崩溃

C++ 使用自定义IDocHostUIHandler并关闭窗口时崩溃,c++,webbrowser-control,c++builder,mshtml,twebbrowser,C++,Webbrowser Control,C++builder,Mshtml,Twebbrowser,我使用定制的IDocHostUIHandler连接到TWebBrowser(在设计模式下)。它起作用了。但是,当程序退出(或使用它的窗口关闭)时,它会崩溃。我想有些东西没有被正确地删除/销毁。我假设自定义IDocHostUIHandler在销毁后仍在使用,因此我应该先销毁web浏览器(或分离自定义) 所以我的问题是-如何正确地销毁自定义IDocHostUIHandler,以便在现有程序时不会崩溃或分离自定义IDocHostUIHandler 如果我在构造函数中删除diCustDoc->SetUI

我使用定制的
IDocHostUIHandler
连接到TWebBrowser(在设计模式下)。它起作用了。但是,当程序退出(或使用它的窗口关闭)时,它会崩溃。我想有些东西没有被正确地删除/销毁。我假设自定义IDocHostUIHandler在销毁后仍在使用,因此我应该先销毁web浏览器(或分离自定义)

所以我的问题是-如何正确地销毁自定义
IDocHostUIHandler
,以便在现有程序时不会崩溃或分离自定义
IDocHostUIHandler

如果我在构造函数中删除
diCustDoc->SetUIHandler(piDocUIHandler)
,它工作时不会出现任何崩溃,因此问题肯定是由附加自定义
IDocHostUIHandler
引起的

在上述
Release()
(在析构函数中)崩溃之前,设置
diCustDoc->SetUIHandler(NULL);

我的自定义
IDocHostUIHandler
(替换弹出菜单并自定义
GetHostInfo

在此处找到的代码:


保存默认的IDocHostUIHandler。不确定是否需要它,但那里的指南告诉我们如何避免内存泄漏以执行
IObjectWithSite::SetSite(NULL)
-不确定这是否适用于此代码。

您没有正确地对
TDocUIHandler
对象执行引用计数

该对象的refcount最初为0。您的表单维护对该对象的活动引用(仅供参考,它应该在类数据成员中,而不是在全局变量中),但不会相应地增加其refcount。因此,当调用
SetUIHandler()
时,它会保存自己对该对象的引用并调用
AddRef()
,因此对象的refcount为1,即使它实际上有2个活动引用

当调用表单析构函数时,它将
Release()
作为对象,将refcount减为0,因此对象
delete
本身,即使WebBrowser仍有对它的活动引用。当WebBrowser正在清理时,它会尝试
Release()
它对该对象的引用会崩溃,因为它不知道该对象已被销毁

试试这个:

IDocHostUIHandler*piDocUIHandler;
__fastcall TForm1::TForm1(TComponent*Owner):TForm(Owner)
{
piDocUIHandler=新的TDocUIHandler(PopupMenu1);
piDocUIHandler->AddRef();//Release();
}
或者:


DelphiInterface piDocUIHandler;//您没有正确地对
TDocUIHandler
对象执行引用计数

该对象的refcount最初为0。您的表单维护对该对象的活动引用(仅供参考,它应该在类数据成员中,而不是在全局变量中),但不会相应地增加其refcount。因此,当调用
SetUIHandler()
时,它会保存自己对该对象的引用并调用
AddRef()
,因此对象的refcount为1,即使它实际上有2个活动引用

当调用表单析构函数时,它将
Release()
作为对象,将refcount减为0,因此对象
delete
本身,即使WebBrowser仍有对它的活动引用。当WebBrowser正在清理时,它会尝试
Release()
它对该对象的引用会崩溃,因为它不知道该对象已被销毁

试试这个:

IDocHostUIHandler*piDocUIHandler;
__fastcall TForm1::TForm1(TComponent*Owner):TForm(Owner)
{
piDocUIHandler=新的TDocUIHandler(PopupMenu1);
piDocUIHandler->AddRef();//Release();
}
或者:


DelphiInterface piDocUIHandler;//您的解释当然有道理,但是为什么如果我中断已实现的
Release()
方法,返回值
res
永远不会达到0?在另一个项目中,它在CodeGuard中也会崩溃,但我认为这是由于与我正在从该项目中删除的EmbeddedWB冲突(与不使用EmbeddedWB的空白新项目一样,CodeGuard对同一代码保持沉默)。仍然在这两个项目中,
res
对于
ULONG res
返回值永远不会达到0,最后一个总是在退出之前为1。@Coder12345对于自动创建的
TForm
,例如
MainForm
,其析构函数直到
WinMain()之后才被调用
t应用程序
对象被销毁时退出。您对此负责吗?您的解释当然有道理,但为什么我要中断已实现的
Release()
method返回值
res
?在另一个项目中,它在CodeGuard中也会崩溃,但我认为这是由于与我正在从该项目中删除的EmbeddedWB冲突(就像在一个不使用EmbeddedWB的空白新项目中一样,CodeGuard对同一代码保持沉默)。仍然在这两个项目中,
res
对于
ULONG res
返回值永远不会达到0,最后一个总是在退出之前为1。@Coder12345对于自动创建的
TForm
,例如
MainForm
,其析构函数直到
WinMain()之后才被调用
t应用程序
对象被销毁时退出。您对此负责吗?
    class TDocUIHandler : public ::IDocHostUIHandler
        {
        private:
            ULONG        RefCount;
            TPopupMenu* pPopupMenu;

        public:
            //TDocUIHandler()                     : RefCount(0)                         {}
            TDocUIHandler(TPopupMenu* fPopupMenu) : RefCount(0), pPopupMenu(fPopupMenu) {}

            // IUnknown method
            HRESULT __stdcall QueryInterface(REFIID riid, void **ppv)
                {
                if (!ppv) return E_POINTER;

                if        (IsEqualIID(riid, IID_IUnknown))          *ppv = static_cast<IUnknown*>(this);
                else if (IsEqualIID(riid, ::IID_IDocHostUIHandler)) *ppv = static_cast< ::IDocHostUIHandler*>(this);
                else                                                *ppv = NULL;

                if (*ppv)
                    {
                    AddRef();                                                // Used the first time so increase the RefCount
                    return S_OK;
                    }

                return E_NOINTERFACE;
                }

            ULONG __stdcall AddRef()
                {
                return (ULONG) InterlockedIncrement((long*)&RefCount);
                }

            ULONG __stdcall Release()
                {
                ULONG res = (ULONG) InterlockedDecrement((long*)&RefCount);
                if (res == 0) delete this;

                return res;
                }

            // Returning S_OK tells the web browser that it need not display its
            // own context menu, presumably because the application hosting it has
            // displayed its own menu to replace it.
            // Since our host does not display any, no context menu is shown.

            STDMETHOD(ShowContextMenu)(         /* [in] */ DWORD dwID,
                                                /* [in] */ POINT __RPC_FAR *ppt,
                                                /* [in] */ IUnknown __RPC_FAR *pcmdtReserved,
                                                /* [in] */ IDispatch __RPC_FAR *pdispReserved)
                {
                // https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa753264(v%3Dvs.85)
                switch (dwID)
                    {
                    default:                    break;
                    case CONTEXT_MENU_DEFAULT:
                    case CONTEXT_MENU_IMAGE:    pPopupMenu->Popup(ppt->x, ppt->y);
                                                break;
                    }

                return S_OK;
                }

            STDMETHOD(GetHostInfo)(                /* [out][in] */ DOCHOSTUIINFO __RPC_FAR *pInfo)
                {
                if (pInfo == NULL) return E_POINTER;

                pInfo->cbSize = sizeof(DOCHOSTUIINFO);
                pInfo->pchHostCss       = NULL;
                pInfo->pchHostNS        = NULL;
                pInfo->dwDoubleClick    = ::DOCHOSTUIDBLCLK_DEFAULT;  // default action

                pInfo->dwFlags          = 0
                                        | ::DOCHOSTUIFLAG_DIV_BLOCKDEFAULT
                                        | ::DOCHOSTUIFLAG_ENABLE_FORMS_AUTOCOMPLETE
                                        | ::DOCHOSTUIFLAG_THEME
                                        | ::DOCHOSTUIFLAG_DPI_AWARE
                                        ;

                return S_OK;
                }

            STDMETHOD(ShowUI)(                  /* [in] */ DWORD dwID,
                                                /* [in] */ IOleInPlaceActiveObject __RPC_FAR *pActiveObject,
                                                /* [in] */ IOleCommandTarget __RPC_FAR *pCommandTarget,
                                                /* [in] */ IOleInPlaceFrame __RPC_FAR *pFrame,
                                                /* [in] */ IOleInPlaceUIWindow __RPC_FAR *pDoc)
                {
                return E_NOTIMPL;
                }

            STDMETHOD(HideUI)(void)
                {
                return E_NOTIMPL;
                }

            STDMETHOD(UpdateUI)(void)
                {
                return E_NOTIMPL;
                }

            STDMETHOD(EnableModeless)(          /* [in] */ BOOL fEnable)
                {
                return E_NOTIMPL;
                }

            STDMETHOD(OnDocWindowActivate)(        /* [in] */ BOOL fActivate)
                {
                return E_NOTIMPL;
                }

            STDMETHOD(OnFrameWindowActivate)(   /* [in] */ BOOL fActivate)
                {
                return E_NOTIMPL;
                }

            STDMETHOD(ResizeBorder)(            /* [in] */ LPCRECT prcBorder,
                                                /* [in] */ IOleInPlaceUIWindow __RPC_FAR *pUIWindow,
                                                /* [in] */ BOOL fRameWindow)
                {
                return E_NOTIMPL;
                }

            STDMETHOD(TranslateAccelerator)(    /* [in] */ LPMSG lpMsg,
                                                /* [in] */ const GUID __RPC_FAR *pguidCmdGroup,
                                                /* [in] */ DWORD nCmdID)
                {
                return E_NOTIMPL;
                }

            STDMETHOD(GetOptionKeyPath)(        /* [out] */ LPOLESTR __RPC_FAR *pchKey,
                                                /* [in] */ DWORD dw)
                {
                return E_NOTIMPL;
                }

            STDMETHOD(GetDropTarget)(           /* [in] */ IDropTarget __RPC_FAR *pDropTarget,
                                                /* [out] */ IDropTarget __RPC_FAR *__RPC_FAR *ppDropTarget)
                {
                return E_NOTIMPL;
                }

            STDMETHOD(GetExternal)(                /* [out] */ IDispatch __RPC_FAR *__RPC_FAR *ppDispatch)
                {
                return E_NOTIMPL;
                }

            STDMETHOD(TranslateUrl)(            /* [in] */ DWORD dwTranslate,
                                                /* [in] */ OLECHAR __RPC_FAR *pchURLIn,
                                                /* [out] */ OLECHAR __RPC_FAR *__RPC_FAR *ppchURLOut)
                {
                return E_NOTIMPL;
                }

            STDMETHOD(FilterDataObject)(        /* [in] */ IDataObject __RPC_FAR *pDO,
                                                /* [out] */ IDataObject __RPC_FAR *__RPC_FAR *ppDORet)
                {
                return E_NOTIMPL;
                }
        };
TDocUIHandler* piDocUIHandler;

__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
piDocUIHandler = new TDocUIHandler(PopupMenu1);

WB->Navigate("about:blank");
while (WB->Busy) { Application->ProcessMessages(); Sleep(50); }

DelphiInterface<IHTMLDocument2> diDoc = WB->Document;
if (diDoc)
    {
    diDoc->designMode = "on";

    DelphiInterface< ::ICustomDoc> diCustDoc;
    if (SUCCEEDED(WB->Document->QueryInterface( ::IID_ICustomDoc,(void**)&diCustDoc)) && diCustDoc)
        {
        if (SUCCEEDED(diCustDoc->SetUIHandler(piDocUIHandler)))
        {
        //MSGBOX("Success!");
        }
    else
        {
        // FAIL
        }
    }
}
__fastcall TForm1::~TForm1()
    {
    piDocUIHandler->Release();
    }