Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Crash during "scalar deleting destructor" with IDocHostUIHandler!

56 views
Skip to first unread message

Chris Shearer Cooper

unread,
Dec 14, 2006, 7:37:49 PM12/14/06
to
Sorry for the cross-post, I'm not sure where this problem is coming from, so
I don't know which group is most likely to be able to help.

In my MFC C++ app, I'm creating a browser window inside a dialog, and I want
to have it be able to communicate with my application. It seems like the
way to do this, is to create a class that implements IDocHostUIHandler, pass
it into the ICustomDoc::SetUIHandler(), and then implement a dispatch class
(one that implements IDispatch) which I return when the HTML control calls
my IDocHostUIHandler::GetExternal.

So far so good. I have a class that implements IDocHostUIHandler, and it is
getting called on a variety of methods (ShowUI, HideUI, etc.) so that's
working.

However, now I have a class that derives from CCmdTarget and calls
EnableAutomation in its constructor, so it should be a happy IDispatch kind
of guy. When my IDocHostUIHandler::GetExternal is called, I 'new' up one of
those, call its InternalAddRef(), and then store its address into the
ppDispatch passed to me in the GetExternal call. I can step through that
with the debugger, but as soon as that function returns, I get a C0000005
exception.

Is there something special I need to be doing in this CCmdTarget-derived
class? Or something different I need to do in my
IDocHostUIHandler::GetExternal?

Thanks!
Chris

=======================
class CDocHostUIHandler : public IDocHostUIHandler, IOleCommandTarget
...
virtual HRESULT STDMETHODCALLTYPE GetExternal(
/* [out] */ IDispatch __RPC_FAR *__RPC_FAR *ppDispatch)
{
TRACE(L"CDocHostUIHandler::GetExternal(ppDispatch=%p)\n", ppDispatch);
External* pExt = new External;
pExt->InternalAddRef();
*ppDispatch = (IDispatch*)pExt;
return S_OK;
}
...
====================
class External : public CCmdTarget
{
DECLARE_DYNAMIC(External)

public:
External(void);
virtual ~External();

// Attributes
public:
protected:

#ifdef _DEBUG
///// NOTICE - NONE OF THESE FUNCTIONS EVER GET CALLED
virtual BOOL GetDispatchIID(IID* pIID)
{
TRACE(L"External::GetDispatchIID()\n");
return CCmdTarget::GetDispatchIID(pIID);
}
virtual UINT GetTypeInfoCount()
{
TRACE(L"External::GetTypeInfoCount()\n");
return CCmdTarget::GetTypeInfoCount();
}
virtual CTypeLibCache* GetTypeLibCache()
{
TRACE(L"External::GetTypeLibCache()\n");
return CCmdTarget::GetTypeLibCache();
}
virtual HRESULT GetTypeLib(LCID lcid, LPTYPELIB* ppTypeLib)
{
TRACE(L"External::GetTypeLib()\n");
return CCmdTarget::GetTypeLib(lcid, ppTypeLib);
}
#endif

// Operations
public:

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(External)
public:
virtual void OnFinalRelease();
//}}AFX_VIRTUAL

// Implementation
protected:

// Generated message map functions
//{{AFX_MSG(External)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG

DECLARE_MESSAGE_MAP()
// Generated OLE dispatch map functions
//{{AFX_DISPATCH(External)
afx_msg void PopulateWindow(LPCTSTR lpszSection);
//}}AFX_DISPATCH
DECLARE_DISPATCH_MAP()
DECLARE_INTERFACE_MAP()
};
=====================================
// External.cpp : implementation file
//

#include "stdafx.h"
#include "External.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;

// External

IMPLEMENT_DYNAMIC(External, CCmdTarget)

External::External(void)
{
TRACE(L"External::External() entered [this=%p]\n", this);

EnableAutomation();
}

External::~External()
{
// =============== NEVER GETS CALLED
TRACE(L"External::~External() entered [this=%p]\n", this);
}


void External::OnFinalRelease()
{
///// ====== NEVER GETS CALLED
TRACE(L"External::OnFinalRelease()\n");

// When the last reference for an automation object is released
// OnFinalRelease is called. The base class will automatically
// deletes the object. Add additional cleanup required for your
// object before calling the base class.

CCmdTarget::OnFinalRelease();
}


BEGIN_MESSAGE_MAP(External, CCmdTarget)
//{{AFX_MSG_MAP(External)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

BEGIN_DISPATCH_MAP(External, CCmdTarget)
//{{AFX_DISPATCH_MAP(External)
DISP_FUNCTION(External, "PopulateWindow", PopulateWindow, VT_EMPTY,
VTS_BSTR)
//}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()

// {27FD7E29-B451-46c9-8234-F285DAEE2567}
static const IID IID_IExternal =
{ 0x27fd7e29, 0xb451, 0x46c9, { 0x82, 0x34, 0xf2, 0x85, 0xda, 0xee, 0x25,
0x67 } };

BEGIN_INTERFACE_MAP(External, CCmdTarget)
INTERFACE_PART(External, IID_IExternal, Dispatch)
END_INTERFACE_MAP()

/////////////////////////////////////////////////////////////////////////////
// External message handlers


void External::PopulateWindow(LPCTSTR lpszSection)
{
TRACE(L"External::PopulateWindow(lpszSection=\"%s\")\n", lpszSection);
}

Igor Tandetnik

unread,
Dec 14, 2006, 8:47:27 PM12/14/06
to
"Chris Shearer Cooper" <chri...@sc3.net> wrote in message
news:12o3rmp...@corp.supernews.com

> In my MFC C++ app, I'm creating a browser window inside a dialog, and
> I want to have it be able to communicate with my application. It
> seems like the way to do this, is to create a class that implements
> IDocHostUIHandler, pass it into the ICustomDoc::SetUIHandler(), and
> then implement a dispatch class (one that implements IDispatch) which
> I return when the HTML control calls my
> IDocHostUIHandler::GetExternal.

You don't need to use ICustomDoc when hosting WebBrowser control. See
Driller sample for details.

> However, now I have a class that derives from CCmdTarget and calls
> EnableAutomation in its constructor, so it should be a happy
> IDispatch kind of guy. When my IDocHostUIHandler::GetExternal is
> called, I 'new' up one of those, call its InternalAddRef(), and then
> store its address into the ppDispatch passed to me in the GetExternal
> call. I can step through that with the debugger, but as soon as that
> function returns, I get a C0000005 exception.
>

> *ppDispatch = (IDispatch*)pExt;

The exception is due to this cast. You need to use
CCmdTarget::GetIDispatch to obtain IDispatch* pointer.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925


Chris Shearer Cooper

unread,
Dec 14, 2006, 9:30:11 PM12/14/06
to
Bingo! Thank you!

"Igor Tandetnik" <itand...@mvps.org> wrote in message
news:OCpG6u%23HHH...@TK2MSFTNGP02.phx.gbl...

Chris Shearer Cooper

unread,
Dec 14, 2006, 9:57:35 PM12/14/06
to
Here's something I don't understand though ...

/* virtual */ HRESULT CHtmlDlg::CDocHostUIHandler::GetExternal(


/* [out] */ IDispatch __RPC_FAR *__RPC_FAR *ppDispatch)
{
TRACE(L"CDocHostUIHandler::GetExternal(ppDispatch=%p)\n", ppDispatch);

External* pExt = new External;

*ppDispatch = pExt->GetIDispatch(FALSE);
return S_OK;
}

If I specify TRUE in the GetIDispatch() call, my 'External' object never
gets deleted. If I specify FALSE, it works fine.

Is there an implicit AddRef() going on in the CCmdTarget constructor or
something?

Thanks,
Chris

"Igor Tandetnik" <itand...@mvps.org> wrote in message
news:OCpG6u%23HHH...@TK2MSFTNGP02.phx.gbl...

Doug Harrison [MVP]

unread,
Dec 14, 2006, 10:26:00 PM12/14/06
to
On Thu, 14 Dec 2006 19:57:35 -0700, "Chris Shearer Cooper"
<chri...@sc3.net> wrote:

>Here's something I don't understand though ...
>
>/* virtual */ HRESULT CHtmlDlg::CDocHostUIHandler::GetExternal(
> /* [out] */ IDispatch __RPC_FAR *__RPC_FAR *ppDispatch)
>{
> TRACE(L"CDocHostUIHandler::GetExternal(ppDispatch=%p)\n", ppDispatch);
>
> External* pExt = new External;
> *ppDispatch = pExt->GetIDispatch(FALSE);
> return S_OK;
>}
>
>If I specify TRUE in the GetIDispatch() call, my 'External' object never
>gets deleted. If I specify FALSE, it works fine.
>
>Is there an implicit AddRef() going on in the CCmdTarget constructor or
>something?

If you look in the ctor, you'll find the reference count (m_dwRef) starts
off equal to 1.

--
Doug Harrison
Visual C++ MVP

0 new messages