Here's what I did:
- created an instance of IID_IiTunes
- queried for IID_IConnectionPointContainer (CPC)
- query CPC for DIID__IiTunesEvents connection point (CP)
- called CP->Advise() with pointer to my class which inherits
_IiTunesEvents
It doesn't work :( All HRESULTs are successful, however I never receive
any event notification.
I am confused that _IiTunesEvents is defined by Apple as being an
IDispatch. What does this mean to the client side? How do I "register"
as an event sink through IDispatch? Is using the IConnectionPoint
interface incorrect?
Can somebody provide sample code or offer some hints?
Much appreciated,
Mike.
Using MFC, I created a class derived from CCmdTarget. _IiTunesEvents is
derived from IDispatch, so I created a dispatch map that matches the
expected events.
The iTunesEventHandler.h file is:
---------
#if
!defined(AFX_ITUNESEVENTHANDLER_H__42970B2C_41F2_4339_8DCC_9AC7D5550402__INCLUDED_)
#define
AFX_ITUNESEVENTHANDLER_H__42970B2C_41F2_4339_8DCC_9AC7D5550402__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// iTunesEventHandler.h : header file
//
#include "iTunesCOMInterface.h" // from Apple's iTunes SDK
/////////////////////////////////////////////////////////////////////////////
// CiTunesEventHandler command target
class CiTunesEventHandler : public CCmdTarget
{
public:
CiTunesEventHandler();
virtual ~CiTunesEventHandler();
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CiTunesEventHandler)
public:
virtual void OnFinalRelease();
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CiTunesEventHandler)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
// Generated OLE dispatch map functions
//{{AFX_DISPATCH(CiTunesEventHandler)
afx_msg void OnDatabaseChangedEvent(const VARIANT FAR&
deletedObjectIDs, const VARIANT FAR& changedObjectIDs);
afx_msg void OnPlayerPlayEvent(const VARIANT FAR& iTrack);
afx_msg void OnPlayerStopEvent(const VARIANT FAR& iTrack);
afx_msg void OnPlayerPlayingTrackChangedEv(const VARIANT FAR& iTrack);
afx_msg void OnUserInterfaceEnabledEvent();
afx_msg void OnCOMCallsDisabledEvent(short reason);
afx_msg void OnCOMCallsEnabled();
afx_msg void OnQuittingEvent();
afx_msg void OnAboutToPromptUserToQuitEvent();
afx_msg void OnSoundVolumeChangedEvent(long newVolume);
//}}AFX_DISPATCH
DECLARE_DISPATCH_MAP()
DECLARE_INTERFACE_MAP()
LPUNKNOWN GetInterfaceHook(const void *piid);
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately
before the previous line.
#endif //
!defined(AFX_ITUNESEVENTHANDLER_H__42970B2C_41F2_4339_8DCC_9AC7D5550402__INCLUDED_)
---------
The iTunesEventHandler.cpp file is:
---------
// iTunesEventHandler.cpp : implementation file
//
#include "stdafx.h"
#include "iTunesEventHandler.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CiTunesEventHandler
CiTunesEventHandler::CiTunesEventHandler()
{
EnableAutomation();
}
CiTunesEventHandler::~CiTunesEventHandler()
{
}
void CiTunesEventHandler::OnFinalRelease()
{
// 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(CiTunesEventHandler, CCmdTarget)
//{{AFX_MSG_MAP(CiTunesEventHandler)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
BEGIN_DISPATCH_MAP(CiTunesEventHandler, CCmdTarget)
//{{AFX_DISPATCH_MAP(CiTunesEventHandler)
DISP_FUNCTION(CiTunesEventHandler, "OnDatabaseChangedEvent",
OnDatabaseChangedEvent, VT_EMPTY, VTS_VARIANT VTS_VARIANT)
DISP_FUNCTION(CiTunesEventHandler, "OnPlayerPlayEvent",
OnPlayerPlayEvent, VT_EMPTY, VTS_VARIANT)
DISP_FUNCTION(CiTunesEventHandler, "OnPlayerStopEvent",
OnPlayerStopEvent, VT_EMPTY, VTS_VARIANT)
DISP_FUNCTION(CiTunesEventHandler, "OnPlayerPlayingTrackChangedEv",
OnPlayerPlayingTrackChangedEv, VT_EMPTY, VTS_VARIANT)
DISP_FUNCTION(CiTunesEventHandler, "OnUserInterfaceEnabledEvent",
OnUserInterfaceEnabledEvent, VT_EMPTY, VTS_NONE)
DISP_FUNCTION(CiTunesEventHandler, "OnCOMCallsDisabledEvent",
OnCOMCallsDisabledEvent, VT_EMPTY, VTS_I2)
DISP_FUNCTION(CiTunesEventHandler, "OnCOMCallsEnabled",
OnCOMCallsEnabled, VT_EMPTY, VTS_NONE)
DISP_FUNCTION(CiTunesEventHandler, "OnQuittingEvent", OnQuittingEvent,
VT_EMPTY, VTS_NONE)
DISP_FUNCTION(CiTunesEventHandler, "OnAboutToPromptUserToQuitEvent",
OnAboutToPromptUserToQuitEvent, VT_EMPTY, VTS_NONE)
DISP_FUNCTION(CiTunesEventHandler, "OnSoundVolumeChangedEvent",
OnSoundVolumeChangedEvent, VT_EMPTY, VTS_I4)
//}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()
// Note: we add support for IID_IiTunesEventHandler to support typesafe
binding
// from VBA. This IID must match the GUID that is attached to the
// dispinterface in the .ODL file.
// {429DD3C8-703E-4188-960E-A9821F14B04C}
static const IID IID_IiTunesEventHandler =
{ 0x429dd3c8, 0x703e, 0x4188, { 0x96, 0xe, 0xa9, 0x82, 0x1f, 0x14,
0xb0, 0x4c } };
BEGIN_INTERFACE_MAP(CiTunesEventHandler, CCmdTarget)
INTERFACE_PART(CiTunesEventHandler, IID_IiTunesEventHandler, Dispatch)
END_INTERFACE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CiTunesEventHandler message handlers
//////////////////////////////////////////////////////////////////////
LPUNKNOWN CiTunesEventHandler::GetInterfaceHook(const void *piid)
{
REFIID iid = *(IID *) piid;
if (iid == DIID__IiTunesEvents)
return GetIDispatch(FALSE);
else
return NULL;
}
//////////////////////////////////////////////////////////////////////
void CiTunesEventHandler::OnDatabaseChangedEvent(const VARIANT &
/*deletedObjectIDs*/, const VARIANT & /*changedObjectIDs*/)
{
// TODO: Add your dispatch handler code here
}
void CiTunesEventHandler::OnPlayerPlayEvent(const VARIANT & /*iTrack*/)
{
// TODO: Add your dispatch handler code here
}
void CiTunesEventHandler::OnPlayerStopEvent(const VARIANT & /*iTrack*/)
{
// TODO: Add your dispatch handler code here
}
void CiTunesEventHandler::OnPlayerPlayingTrackChangedEv(const VARIANT &
/*iTrack*/)
{
// TODO: Add your dispatch handler code here
}
void CiTunesEventHandler::OnUserInterfaceEnabledEvent()
{
// TODO: Add your dispatch handler code here
}
void CiTunesEventHandler::OnCOMCallsDisabledEvent(short /*reason*/)
{
// TODO: Add your dispatch handler code here
}
void CiTunesEventHandler::OnCOMCallsEnabled()
{
// TODO: Add your dispatch handler code here
}
void CiTunesEventHandler::OnQuittingEvent()
{
// TODO: Add your dispatch handler code here
}
void CiTunesEventHandler::OnAboutToPromptUserToQuitEvent()
{
// TODO: Add your dispatch handler code here
}
void CiTunesEventHandler::OnSoundVolumeChangedEvent(long /*newVolume*/)
{
// TODO: Add your dispatch handler code here
}
-------
In another class, I instantiate a CiTunesEventHandler object and create
a connection point to it from iTunes:
-------
//////////////////////////////////////////////////////////////////////
CComPtr<IiTunes> CiTunesInterface::ITunes()
{
if (m_iTunes == NULL)
{
m_iTunes.CoCreateInstance(CLSID_iTunesApp, NULL,
CLSCTX_LOCAL_SERVER);
CComQIPtr<IConnectionPointContainer> cpCont(m_iTunes);
if (cpCont)
{
if (SUCCEEDED(cpCont->FindConnectionPoint(DIID__IiTunesEvents,
&m_connectionPoint)))
{
CComQIPtr<_IiTunesEvents> ev(m_eventHandler.GetIDispatch(FALSE));
m_connectionPoint->Advise(m_eventHandler.GetIDispatch(FALSE),
&m_cookie);
}
}
}
return m_iTunes;
}
-------
The relevant variables used in the above code are:
-------
CComPtr<IiTunes> m_iTunes;
CComPtr<IConnectionPoint> m_connectionPoint;
DWORD m_cookie;
CiTunesEventHandler m_eventHandler;
-------
Remember to unadvise the connection point when you're shutting down.
Hope this helps someone.
- Bob Alexander