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);
}
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
"Igor Tandetnik" <itand...@mvps.org> wrote in message
news:OCpG6u%23HHH...@TK2MSFTNGP02.phx.gbl...
/* 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...
>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