ATL compiler error
-
It's been ages since I played with this, but do you need to add an entry into the project .idl file defining a GUID for coclass or interface there? Is there even an idl file for this project type?
L u n a t i c F r i n g e
Yes a .idl file was created and it has a GUID in it for the
IMyEventHandler
interface."One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
-
Yes a .idl file was created and it has a GUID in it for the
IMyEventHandler
interface."One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
DavidCrow wrote:
a .idl file was created and it has a GUID in it for the IMyEventHandler interface.
David, I don't get exactly what you're trying to do. It seems like you're trying to create COM server and register something else that you have developed (
CMyEventHandler
?) for receiving COM events. Right? What I'm trying to figure out is why you're trying to create an instance of yourCMyEventhandler
... Is it really a COM server? If so, from where is it created and does the header files created have a CLSID for it? Usually you would create a COM server with e.g.::CoCreateInstance()
, or one of its equivalents. You provide the CLSID for the server, the IID for the desired interface and a pointer to store the interface pointer in if the call was successful. If the server produces COM events that the client is interested in, the client uses a mechanism in the server to register itself as an event listener (Advise()
?). From your explanation I don't see the above happening, a part from callingCreateInstance
but for what looks to me as the "wrong" object. Can you elaborate on this a bit further David?"It's supposed to be hard, otherwise anybody could do it!" - selfquote
"High speed never compensates for wrong direction!" - unknown -
DavidCrow wrote:
a .idl file was created and it has a GUID in it for the IMyEventHandler interface.
David, I don't get exactly what you're trying to do. It seems like you're trying to create COM server and register something else that you have developed (
CMyEventHandler
?) for receiving COM events. Right? What I'm trying to figure out is why you're trying to create an instance of yourCMyEventhandler
... Is it really a COM server? If so, from where is it created and does the header files created have a CLSID for it? Usually you would create a COM server with e.g.::CoCreateInstance()
, or one of its equivalents. You provide the CLSID for the server, the IID for the desired interface and a pointer to store the interface pointer in if the call was successful. If the server produces COM events that the client is interested in, the client uses a mechanism in the server to register itself as an event listener (Advise()
?). From your explanation I don't see the above happening, a part from callingCreateInstance
but for what looks to me as the "wrong" object. Can you elaborate on this a bit further David?"It's supposed to be hard, otherwise anybody could do it!" - selfquote
"High speed never compensates for wrong direction!" - unknownRoger Stoltz wrote:
David, I don't get exactly what you're trying to do. It seems like you're trying to create COM server and register something else that you have developed (CMyEventHandler?) for receiving COM events. Right?
My overall intent is to open a .mp3 file using the Windows Media Player COM object, and then read some information from one of the headers. I can't get this information until the player has loaded the .mp3 file. A side effect of loading the .mp3 file is that it will start playing it. To get around this, I need to respond to the 'play' event and stop it. That's what got me to looking at the
IWMPEvents
interface.Roger Stoltz wrote:
What I'm trying to figure out is why you're trying to create an instance of your CMyEventhandler... Is it really a COM server? If so, from where is it created and does the header files created have a CLSID for it? Usually you would create a COM server with e.g. ::CoCreateInstance(), or one of its equivalents. You provide the CLSID for the server, the IID for the desired interface and a pointer to store the interface pointer in if the call was successful. If the server produces COM events that the client is interested in, the client uses a mechanism in the server to register itself as an event listener (Advise()?). From your explanation I don't see the above happening, a part from calling CreateInstance but for what looks to me as the "wrong" object. Can you elaborate on this a bit further David?
Good questions. As I've done very little with COM, some of the terms and procedures are still a mystery. Other pieces of my code look like:
CComPtr<IWMPPlayer4> player;
HRESULT hr = player.CoCreateInstance(__uuidof(WindowsMediaPlayer), 0, CLSCTX_INPROC_SERVER);CComPtr<IConnectionPoint> connectionPoint;
CComPtr<IConnectionPointContainer> connectionContainer;
player->QueryInterface(&connectionContainer);
connectionContainer->FindConnectionPoint(__uuidof(IWMPEvents), &connectionPoint);"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
-
Roger Stoltz wrote:
David, I don't get exactly what you're trying to do. It seems like you're trying to create COM server and register something else that you have developed (CMyEventHandler?) for receiving COM events. Right?
My overall intent is to open a .mp3 file using the Windows Media Player COM object, and then read some information from one of the headers. I can't get this information until the player has loaded the .mp3 file. A side effect of loading the .mp3 file is that it will start playing it. To get around this, I need to respond to the 'play' event and stop it. That's what got me to looking at the
IWMPEvents
interface.Roger Stoltz wrote:
What I'm trying to figure out is why you're trying to create an instance of your CMyEventhandler... Is it really a COM server? If so, from where is it created and does the header files created have a CLSID for it? Usually you would create a COM server with e.g. ::CoCreateInstance(), or one of its equivalents. You provide the CLSID for the server, the IID for the desired interface and a pointer to store the interface pointer in if the call was successful. If the server produces COM events that the client is interested in, the client uses a mechanism in the server to register itself as an event listener (Advise()?). From your explanation I don't see the above happening, a part from calling CreateInstance but for what looks to me as the "wrong" object. Can you elaborate on this a bit further David?
Good questions. As I've done very little with COM, some of the terms and procedures are still a mystery. Other pieces of my code look like:
CComPtr<IWMPPlayer4> player;
HRESULT hr = player.CoCreateInstance(__uuidof(WindowsMediaPlayer), 0, CLSCTX_INPROC_SERVER);CComPtr<IConnectionPoint> connectionPoint;
CComPtr<IConnectionPointContainer> connectionContainer;
player->QueryInterface(&connectionContainer);
connectionContainer->FindConnectionPoint(__uuidof(IWMPEvents), &connectionPoint);"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
DavidCrow wrote:
My overall intent is to open a .mp3 file using the Windows Media Player COM object, and then read some information from one of the headers.
Perhaps this is not what you'd like to hear/read, but wouldn't it suffice to read the mp3 file from your application if you're only interested in the header? I guess you've thought about this alternative already and discarded it. If not, you may find this[^] or this[^] useful. I don't know what header information you're looking for. More about the Media Player solution... Have you had a look at this article[^] about handling Media Player events in C++? Provided that you successfully can create the Media Player server, you should be able to find something in the article above that you can use. You should also have a look at the ATL sample that demonstrates connection points: ATLDuck.
"It's supposed to be hard, otherwise anybody could do it!" - selfquote
"High speed never compensates for wrong direction!" - unknown -
DavidCrow wrote:
My overall intent is to open a .mp3 file using the Windows Media Player COM object, and then read some information from one of the headers.
Perhaps this is not what you'd like to hear/read, but wouldn't it suffice to read the mp3 file from your application if you're only interested in the header? I guess you've thought about this alternative already and discarded it. If not, you may find this[^] or this[^] useful. I don't know what header information you're looking for. More about the Media Player solution... Have you had a look at this article[^] about handling Media Player events in C++? Provided that you successfully can create the Media Player server, you should be able to find something in the article above that you can use. You should also have a look at the ATL sample that demonstrates connection points: ATLDuck.
"It's supposed to be hard, otherwise anybody could do it!" - selfquote
"High speed never compensates for wrong direction!" - unknownRoger Stoltz wrote:
Have you had a look at this article[^] about handling Media Player events in C++?
Yes, several times.
Roger Stoltz wrote:
Provided that you successfully can create the Media Player server, you should be able to find something in the article above that you can use.
I can play the .mp3 file just fine. I can also change other settings (e.g., auto start). It's just getting past the "no GUID specified" compiler error that's troubling me.
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
-
Roger Stoltz wrote:
Have you had a look at this article[^] about handling Media Player events in C++?
Yes, several times.
Roger Stoltz wrote:
Provided that you successfully can create the Media Player server, you should be able to find something in the article above that you can use.
I can play the .mp3 file just fine. I can also change other settings (e.g., auto start). It's just getting past the "no GUID specified" compiler error that's troubling me.
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
DavidCrow wrote:
It's just getting notified of events that's troubling me.
Okay... Basically this is what you have to do:
- Implement a class that derives from the event interface you're interested in and put the interface in the COM_MAP. As I understand it you've already done this part.
- When you've successfully created the Media Player server and got an interface pointer (
IWMPPlayer
), you create an instance of the class mentioned above; not by usingCreateInstance()
, usenew
or similar (you know what I mean). - Ask
IWMPPlayer
for theIConnectionPointContainer
interface as described in the article. - Find the connection point you want,
IWMPEvents
, by callingIConnectionPointContainer::FindConnectionPoint()
and you should get anIConnectionPoint
interface in return as described in the article. - Register your class as an event listener by calling
IConnectionPoint::Advise()
and provide a pointer to your instance of yourCMyEventHandler
. Store the cookie and theIConnectionPoint
interface pointer as you'll need it when you unregister from the server. - You should be all set to catch events from Media Player!
- Remember to call
IConnectionPoint::Unadvise()
when you're done.
The ATLDuck sample[^] explains how to set up connection point further. It gives you a complete working example and not just some code snippets.
"It's supposed to be hard, otherwise anybody could do it!" - selfquote
"High speed never compensates for wrong direction!" - unknown -
DavidCrow wrote:
It's just getting notified of events that's troubling me.
Okay... Basically this is what you have to do:
- Implement a class that derives from the event interface you're interested in and put the interface in the COM_MAP. As I understand it you've already done this part.
- When you've successfully created the Media Player server and got an interface pointer (
IWMPPlayer
), you create an instance of the class mentioned above; not by usingCreateInstance()
, usenew
or similar (you know what I mean). - Ask
IWMPPlayer
for theIConnectionPointContainer
interface as described in the article. - Find the connection point you want,
IWMPEvents
, by callingIConnectionPointContainer::FindConnectionPoint()
and you should get anIConnectionPoint
interface in return as described in the article. - Register your class as an event listener by calling
IConnectionPoint::Advise()
and provide a pointer to your instance of yourCMyEventHandler
. Store the cookie and theIConnectionPoint
interface pointer as you'll need it when you unregister from the server. - You should be all set to catch events from Media Player!
- Remember to call
IConnectionPoint::Unadvise()
when you're done.
The ATLDuck sample[^] explains how to set up connection point further. It gives you a complete working example and not just some code snippets.
"It's supposed to be hard, otherwise anybody could do it!" - selfquote
"High speed never compensates for wrong direction!" - unknownIt appears that I have steps 1-5 in place. Do you agree? Does the duck sample talk about how to avoid the GUID error that I'm battling?
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
-
It appears that I have steps 1-5 in place. Do you agree? Does the duck sample talk about how to avoid the GUID error that I'm battling?
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
DavidCrow wrote:
It appears that I have steps 1-5 in place. Do you agree?
Nope, I don't agree. Not unless you've altered the code you presented earlier where you tried to create an instance of
CMyEventHandler
by callingCreateInstance()
into what I suggested, e.g. usingnew
.DavidCrow wrote:
Does the duck sample talk about how to avoid the GUID error that I'm battling?
Nope. The question is irrelevant as a CLSID for
CMyEventHandler
won't be needed when you create aCMyEventHandler
on the heap or the stack. Note that what the compiler complains about is a missing "Class ID", CLSID, since it refers to the 'object'CMyEventHandler
. The CLSID is the identity of the server one is trying to create with a call toCreateInstance()
. This is not the same as the identity of the interface you're trying to use called "Interface ID" or IID, which also has a Globally Unique IDentifier assigned to it. YourCMyEventHandler
declaration should look something like this:class ATL_NO_VTABLE CMyEventHandler :
public CComObjectRootEx<CComSingleThreadModel>,
public IWMPEvents
{
public:
BEGIN_COM_MAP( CMyEventHandler )
COM_INTERFACE_ENTRY(IWMPEvents)
END_COM_MAP()public: /\* Here goes declarations of the functions in the IWMPEvents interface \*/
};
The code where you create the Media Player server should look something like this, as partially described in the article:
CComPtr<IWMPPlayer> spWMPPlayer;
CComPtr<IConnectionPoint> spConnectionPoint;
DWORD dwAdviseCookie;
HRESULT hr;/* I don't know the CLSID or ProgID of the Media Player server as I'm currently sitting on an
** Ubuntu machine at home, but let's just assume you've successfully created the Media Player
** server and you have a valid interface pointer for it: spWMPPlayer.
** Anyway you seem to have taken care of that already. ;-)
*//* Create the CMyEventHandler object */
CMyEventHandler* pMyEventHandler = new CComObject<CMyEventHandler>;/* Get the connection point */
CComQIPtr<IConnectionPointContainer, &__uuidof(IConnectionPointContainer)> spConnectionContainer( spWMPPlayer );
if( spConnectionContainer )
{
hr = spConnectionContainer->FindConnectionPoint( __uuidof(IWMPEvents), &spConnectionPoint )
if( pMyEventHandler && SU -
DavidCrow wrote:
It appears that I have steps 1-5 in place. Do you agree?
Nope, I don't agree. Not unless you've altered the code you presented earlier where you tried to create an instance of
CMyEventHandler
by callingCreateInstance()
into what I suggested, e.g. usingnew
.DavidCrow wrote:
Does the duck sample talk about how to avoid the GUID error that I'm battling?
Nope. The question is irrelevant as a CLSID for
CMyEventHandler
won't be needed when you create aCMyEventHandler
on the heap or the stack. Note that what the compiler complains about is a missing "Class ID", CLSID, since it refers to the 'object'CMyEventHandler
. The CLSID is the identity of the server one is trying to create with a call toCreateInstance()
. This is not the same as the identity of the interface you're trying to use called "Interface ID" or IID, which also has a Globally Unique IDentifier assigned to it. YourCMyEventHandler
declaration should look something like this:class ATL_NO_VTABLE CMyEventHandler :
public CComObjectRootEx<CComSingleThreadModel>,
public IWMPEvents
{
public:
BEGIN_COM_MAP( CMyEventHandler )
COM_INTERFACE_ENTRY(IWMPEvents)
END_COM_MAP()public: /\* Here goes declarations of the functions in the IWMPEvents interface \*/
};
The code where you create the Media Player server should look something like this, as partially described in the article:
CComPtr<IWMPPlayer> spWMPPlayer;
CComPtr<IConnectionPoint> spConnectionPoint;
DWORD dwAdviseCookie;
HRESULT hr;/* I don't know the CLSID or ProgID of the Media Player server as I'm currently sitting on an
** Ubuntu machine at home, but let's just assume you've successfully created the Media Player
** server and you have a valid interface pointer for it: spWMPPlayer.
** Anyway you seem to have taken care of that already. ;-)
*//* Create the CMyEventHandler object */
CMyEventHandler* pMyEventHandler = new CComObject<CMyEventHandler>;/* Get the connection point */
CComQIPtr<IConnectionPointContainer, &__uuidof(IConnectionPointContainer)> spConnectionContainer( spWMPPlayer );
if( spConnectionContainer )
{
hr = spConnectionContainer->FindConnectionPoint( __uuidof(IWMPEvents), &spConnectionPoint )
if( pMyEventHandler && SURoger Stoltz wrote:
I hope you'll find the above helpful.
Yes, the compiler is happy now. It's still a tad confusing, however, since the two examples I was using as a reference were calling
CreateInstance()
. Upon running the code,Advise()
is returning 0x80040202 (CONNECT_E_CANNOTCONNECT
). MSDN article Q183216 talks about my sink object (CMyEventHandler
) may be missing something thatQueryInterface()
is looking for. As far as I can tell, my sink object has implemented all of theIWMPEvents
methods."One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
-
Roger Stoltz wrote:
I hope you'll find the above helpful.
Yes, the compiler is happy now. It's still a tad confusing, however, since the two examples I was using as a reference were calling
CreateInstance()
. Upon running the code,Advise()
is returning 0x80040202 (CONNECT_E_CANNOTCONNECT
). MSDN article Q183216 talks about my sink object (CMyEventHandler
) may be missing something thatQueryInterface()
is looking for. As far as I can tell, my sink object has implemented all of theIWMPEvents
methods."One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
DavidCrow wrote:
MSDN article Q183216 talks about my sink object (CMyEventHandler) may be missing something that QueryInterface() is looking for. As far as I can tell, my sink object has implemented all of the IWMPEvents methods.
The article Q183216 is talking about when the server is querying for the source interface, IWMPEvents in your case, and the client who is supposed to implement the interface responds with an error that says the interface is not supported/implemented. The error returned to the server is most likely
E_NOINTERFACE
. For this to be applicable in your situation you must have forgotten to put the entry in theCOM_MAP
, but as I understand from your previous posts you've already got that in place. This made me wonder if the server might be requesting another interface such asIDispatch
, e.g. if theIWMPEvents
inherits fromIDispatch
, but as far as I can tell with the OLEView tool this is not the case. Can you successfully "find" the connection point withIConnectionPointContainer::FindConnectionPoint()
? Are you possibly making the call from a worker thread? If you are, does it work if you try to do this from your main thread?"It's supposed to be hard, otherwise anybody could do it!" - selfquote
"High speed never compensates for wrong direction!" - unknown -
DavidCrow wrote:
MSDN article Q183216 talks about my sink object (CMyEventHandler) may be missing something that QueryInterface() is looking for. As far as I can tell, my sink object has implemented all of the IWMPEvents methods.
The article Q183216 is talking about when the server is querying for the source interface, IWMPEvents in your case, and the client who is supposed to implement the interface responds with an error that says the interface is not supported/implemented. The error returned to the server is most likely
E_NOINTERFACE
. For this to be applicable in your situation you must have forgotten to put the entry in theCOM_MAP
, but as I understand from your previous posts you've already got that in place. This made me wonder if the server might be requesting another interface such asIDispatch
, e.g. if theIWMPEvents
inherits fromIDispatch
, but as far as I can tell with the OLEView tool this is not the case. Can you successfully "find" the connection point withIConnectionPointContainer::FindConnectionPoint()
? Are you possibly making the call from a worker thread? If you are, does it work if you try to do this from your main thread?"It's supposed to be hard, otherwise anybody could do it!" - selfquote
"High speed never compensates for wrong direction!" - unknownRoger Stoltz wrote:
The error returned to the server is most likely E_NOINTERFACE.
Which is
0x8004002
. The error that I am getting is0x80040202
.Roger Stoltz wrote:
For this to be applicable in your situation you must have forgotten to put the entry in the COM_MAP, but as I understand from your previous posts you've already got that in place. This made me wonder if the server might be requesting another interface such as IDispatch, e.g. if the IWMPEvents inherits from IDispatch, but as far as I can tell with the OLEView tool this is not the case.
class ATL_NO_VTABLE CMyEventHandler :
public CComObjectRootEx,
public CComCoClass,
public IDispatchImpl,
public IWMPEvents
{
public:
CMyEventHandler() {}DECLARE_REGISTRY_RESOURCEID(IDR_MYEVENTHANDLER)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CMyEventHandler)
COM_INTERFACE_ENTRY(IMyEventHandler)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IWMPEvents)
END_COM_MAP()...
};Roger Stoltz wrote:
Can you successfully "find" the connection point with IConnectionPointContainer::FindConnectionPoint()?
QueryInterface()
andFindConnectionPoint()
both returnS_OK
.Roger Stoltz wrote:
Are you possibly making the call from a worker thread? If you are, does it work if you try to do this from your main thread?
No additional threads have been created. My call to
Advise()
differs from yours in how I had to cast the first argument:hr = connectionPoint->Advise((IWMPEvents *) pEventHandler, &dwAdviseCookie);
Casting it to
IUnknown*
yielded: error C2594: 'type cast' : ambiguous conversions from 'class CMyEventHandler *' to 'struct IUnknown *'"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
-
Roger Stoltz wrote:
The error returned to the server is most likely E_NOINTERFACE.
Which is
0x8004002
. The error that I am getting is0x80040202
.Roger Stoltz wrote:
For this to be applicable in your situation you must have forgotten to put the entry in the COM_MAP, but as I understand from your previous posts you've already got that in place. This made me wonder if the server might be requesting another interface such as IDispatch, e.g. if the IWMPEvents inherits from IDispatch, but as far as I can tell with the OLEView tool this is not the case.
class ATL_NO_VTABLE CMyEventHandler :
public CComObjectRootEx,
public CComCoClass,
public IDispatchImpl,
public IWMPEvents
{
public:
CMyEventHandler() {}DECLARE_REGISTRY_RESOURCEID(IDR_MYEVENTHANDLER)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CMyEventHandler)
COM_INTERFACE_ENTRY(IMyEventHandler)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IWMPEvents)
END_COM_MAP()...
};Roger Stoltz wrote:
Can you successfully "find" the connection point with IConnectionPointContainer::FindConnectionPoint()?
QueryInterface()
andFindConnectionPoint()
both returnS_OK
.Roger Stoltz wrote:
Are you possibly making the call from a worker thread? If you are, does it work if you try to do this from your main thread?
No additional threads have been created. My call to
Advise()
differs from yours in how I had to cast the first argument:hr = connectionPoint->Advise((IWMPEvents *) pEventHandler, &dwAdviseCookie);
Casting it to
IUnknown*
yielded: error C2594: 'type cast' : ambiguous conversions from 'class CMyEventHandler *' to 'struct IUnknown *'"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
DavidCrow wrote:
Roger Stoltz wrote:
The error returned to the server is most likely E_NOINTERFACE.
Which is 0x8004002. The error that I am getting is 0x80040202.
Well, you're not the server which means that what I'm talking about is the error message your client is sending the Media Player when the Media Player server asks for your implementation of the
IWMPEvents
source interface. David, now I'm just guessing, but I get the impression that you've misinterpreted some part of what I've been trying to explain and I cannot really figure out what part... Most likely I haven't been very clear on the subject so let me try again. It looks like you've opted for my suggestion based on a nested class to use as an event sink, otherwise I don't understand yourpEventHandler
variable as it should bethis
in the call toAdvise()
. WhateverpEventHandler
points to doesn't seem to expose theIWMPEvents
interface judging from the error you got. If you are using the nested class version you should remove theIWMPEvents
entry from the COM_MAP in the outer class and put it into the presumably non-existing COM_MAP of the inner/nested class. You can think of the COM_MAP as being traversed whenQueryInterface()
is called on your object. I don't understand why you're exposing theIMyEventHandler
andIDispatch
interfaces from your class. Perhaps you did it intentionally or it could be a misunderstanding. Who is going to use those interfaces? If you're not trying to develop a COM server yourself that exposes e.g.IMyEventHandler
, then I guess it shouldn't be there in the first place. However, now that you've provided an important part of your class declaration I can try and patch together a declaration based on the nested class scenario for you. I hope things will clear up afterwards. It should look something like this:class ATL_NO_VTABLE CMyEventHandler :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CMyEventHandler, &CLSID_MyEventHandler>,
public IDispatchImpl,
{
public:
CMyEventHandler() {}DECLARE_REGISTRY_RESOURCEID(IDR_MYEVENTHANDLER)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CMyEventHandler)
COM_INTERFACE_ENTRY(IMyEventHandler)
COM_INTERFACE_ENTRY(IDispatch)
END_ -
DavidCrow wrote:
Roger Stoltz wrote:
The error returned to the server is most likely E_NOINTERFACE.
Which is 0x8004002. The error that I am getting is 0x80040202.
Well, you're not the server which means that what I'm talking about is the error message your client is sending the Media Player when the Media Player server asks for your implementation of the
IWMPEvents
source interface. David, now I'm just guessing, but I get the impression that you've misinterpreted some part of what I've been trying to explain and I cannot really figure out what part... Most likely I haven't been very clear on the subject so let me try again. It looks like you've opted for my suggestion based on a nested class to use as an event sink, otherwise I don't understand yourpEventHandler
variable as it should bethis
in the call toAdvise()
. WhateverpEventHandler
points to doesn't seem to expose theIWMPEvents
interface judging from the error you got. If you are using the nested class version you should remove theIWMPEvents
entry from the COM_MAP in the outer class and put it into the presumably non-existing COM_MAP of the inner/nested class. You can think of the COM_MAP as being traversed whenQueryInterface()
is called on your object. I don't understand why you're exposing theIMyEventHandler
andIDispatch
interfaces from your class. Perhaps you did it intentionally or it could be a misunderstanding. Who is going to use those interfaces? If you're not trying to develop a COM server yourself that exposes e.g.IMyEventHandler
, then I guess it shouldn't be there in the first place. However, now that you've provided an important part of your class declaration I can try and patch together a declaration based on the nested class scenario for you. I hope things will clear up afterwards. It should look something like this:class ATL_NO_VTABLE CMyEventHandler :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CMyEventHandler, &CLSID_MyEventHandler>,
public IDispatchImpl,
{
public:
CMyEventHandler() {}DECLARE_REGISTRY_RESOURCEID(IDR_MYEVENTHANDLER)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CMyEventHandler)
COM_INTERFACE_ENTRY(IMyEventHandler)
COM_INTERFACE_ENTRY(IDispatch)
END_Thanks for the help, Roger. I'll eventually get my head wrapped around this.
Roger Stoltz wrote:
Well, you're not the server which means that what I'm talking about is the error message your client is sending the Media Player when the Media Player server asks for your implementation of the IWMPEvents source interface.
I was probably confusing who was the client and who was the server. I'm not intentionally trying to create a server, but rather use the Media Player server.
Roger Stoltz wrote:
Whatever pEventHandler points to doesn't seem to expose the IWMPEvents interface judging from the error you got.
Previously, my
CMyEventHandler
class was derived from, among others,IWMPEvents
, and I thought I had the appropriateIWMPEvents
entry in theBEGIN_COM_MAP()
macro. So I don't understand what the Media Player server could have been asking for that I was not providing/exposing.Roger Stoltz wrote:
I don't understand why you're exposing the IMyEventHandler and IDispatch interfaces from your class. Perhaps you did it intentionally or it could be a misunderstanding. Who is going to use those interfaces? If you're not trying to develop a COM server yourself that exposes e.g. IMyEventHandler, then I guess it shouldn't be there in the first place.
They were added by the ATL Object Wizard. How does moving the
IWMPEvents
interface toCMyEventSink
differ from having it inCMyEventHandler
?"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
-
Thanks for the help, Roger. I'll eventually get my head wrapped around this.
Roger Stoltz wrote:
Well, you're not the server which means that what I'm talking about is the error message your client is sending the Media Player when the Media Player server asks for your implementation of the IWMPEvents source interface.
I was probably confusing who was the client and who was the server. I'm not intentionally trying to create a server, but rather use the Media Player server.
Roger Stoltz wrote:
Whatever pEventHandler points to doesn't seem to expose the IWMPEvents interface judging from the error you got.
Previously, my
CMyEventHandler
class was derived from, among others,IWMPEvents
, and I thought I had the appropriateIWMPEvents
entry in theBEGIN_COM_MAP()
macro. So I don't understand what the Media Player server could have been asking for that I was not providing/exposing.Roger Stoltz wrote:
I don't understand why you're exposing the IMyEventHandler and IDispatch interfaces from your class. Perhaps you did it intentionally or it could be a misunderstanding. Who is going to use those interfaces? If you're not trying to develop a COM server yourself that exposes e.g. IMyEventHandler, then I guess it shouldn't be there in the first place.
They were added by the ATL Object Wizard. How does moving the
IWMPEvents
interface toCMyEventSink
differ from having it inCMyEventHandler
?"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Man who follows car will be exhausted." - Confucius
DavidCrow wrote:
Previously, my
CMyEventHandler
class was derived from, among others,IWMPEvents
, and I thought I had the appropriateIWMPEvents
entry in theBEGIN_COM_MAP()
macro. So I don't understand what the Media Player server could have been asking for that I was not providing/exposing.Yep, but as I understand it you got a compiler error at that time and not the runtime error that says the server cannot find the
IWMPEvents
interface in your client.DavidCrow wrote:
They were added by the ATL Object Wizard.
Okay. You probably used the wizard that is used for creating COM servers. But that's a minor problem, it just made me unsure of what you were trying to do. Never mind.
DavidCrow wrote:
How does moving the
IWMPEvents
interface toCMyEventSink
differ from having it inCMyEventHandler
?In your case it doesn't really make a difference in practice. However, I consider the nested class a more versatile solution or design pattern. One major benefit is to avoid circular references. Consider COM server A that creates another COM server B. A is created by the client C. B exposes a source interface, e.g. a connection point, for which A implements an event sink and register itself for receiving COM events from B. When B requests the interface for the event sink it will increment the reference of A according to COM rules. The problem is that when C wants to destroy A by releasing its last reference, the A reference counter will not reach zero as B still holds a reference to it. This will force a kind of catch 22 situation where neither A nor B will get their last reference released. The root cause is that both C and B uses the same object for reference counting in A. One solution is to create another object, like a nested class inside A, that serves as event sink. My point is that if you master this way of creating an event sink, you'll probably never have to do it in another way. I also consider it more clean from a design point of view.
"It's supposed to be hard, otherwise anybody could do it!" - selfquote
"High speed never compensates for wrong direction!" - unknown