|
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 .
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<CComSingleThreadModel>,
public CComCoClass<CMyEventHandler, &CLSID_MyEventHandler>,
public IDispatchImpl<IMyEventHandler, &IID_IMyEventHandler, &LIBID_MusicTestLib>,
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() and FindConnectionPoint() both return S_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 your pEventHandler variable as it should be this in the call to Advise() . Whatever pEventHandler points to doesn't seem to expose the IWMPEvents interface judging from the error you got.
If you are using the nested class version you should remove the IWMPEvents 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 when QueryInterface() is called on your object.
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.
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_COM_MAP()
protected:
class ATL_NO_VTABLE CMyEventSink :
public CComObjectRootEx<CComSingleThreadModel>,
public IWMPEvents
{
public:
CMyEventSink( CMyEventHandler* pParent = NULL ) { m_pParent = pParent; }
BEGIN_COM_MAP( CMyEventSink )
COM_INTERFACE_ENTRY(IWMPEvents)
END_COM_MAP()
public:
STDMETHOD(PlayStateChanged)( long NewState ) { m_pParent->PlayStateChanged( NewState ); }
protected:
CMyEventHandler* m_pParent;
};
friend class CMyEventSink;
CMyEventSink* m_pMyEventSink;
CComPtr<IConnectionPoint> m_spConnectionPoint;
DWORD m_dwWMPEventsCookie;
void PlayStateChanged( long NewState );
...
};
The nested class CMyEventSink is the only part that is interesting as far as COM events are concerned. Here I just put it inside the outer CMyEventHandler , which seems to be a COM server itself, for clarification reasons and because I guess that you've already started going in this direction. This way you can see that CMyEventHandler exposes the two interfaces IMyEventHandler and IDispatch . The nested class, CMyEventSink , serves no other purpose than acting as an event sink for the IWMPEvents interface.
Given the declaration above, you can hook up for receiving IWMPEvents from the CMyEventHandler class like we've discussed earlier:
CComPtr<IWMPPlayer> spWMPPlayer;
CComPtr<IConnectionPoint> spConnectionPoint;
DWORD dwAdviseCookie;
HRESULT hr;
m_pMyEventSink = new CComObject<CMyEventSink>( this );
CComQIPtr<IConnectionPointContainer, &__uuidof(IConnectionPointContainer)> spConnectionContainer( spWMPPlayer );
if( spConnectionContainer )
{
hr = spConnectionContainer->FindConnectionPoint( __uuidof(IWMPEvents), &m_spConnectionPoint )
if( m_pMyEventSink && SUCCEEDED( hr ) )
{
hr = m_spConnectionPoint->Advise( (IUnknown*)m_pMyEventSink, &m_dwWMPEventsCookie );
}
}
When you're done receiving events from the Media Player, unregister as listener with the following:
m_spConnectionPoint->Unadvise( m_dwWMPEventsCookie );
m_spConnectionPoint.Release();
If you don't get it to work after trying out the above, I need to see your complete CMyEventHandler declaration. Well, you can of course omit the inherited functions from the IWMPEvents interface. I also need the snippet of code where your create whatever you provide in the call to IConnectionPoint::Advise() that should serve as event sink and also where actually make the call to Advise() .
Naturally I don't know anything Media Player specific as I haven't been working with it. Not yet, at least. The parts I've understood to be Media Player specific I have just made qualified guesses and put some mocks to explain the bigger picture. E.g. the method PlayStateChanged() may very well be declared incorrectly and it may not at all be the event callback you need.
I've tried to concentrate on the COM stuff, some ATL quirks and how to set up an event sink the way I usually do it.
Phhwwweeee...... That was a long one, I even got a warning saying it's long when trying to post it....
"It's supposed to be hard, otherwise anybody could do it!" - selfquote "High speed never compensates for wrong direction!" - unknown
|
|
|
|
|
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 appropriate IWMPEvents entry in the BEGIN_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 to CMyEventSink differ from having it in CMyEventHandler ?"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 appropriate IWMPEvents entry in the BEGIN_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 to CMyEventSink differ from having it in CMyEventHandler ?
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
|
|
|
|
|
Hi,
I have looked everywhere on the web a good tutorial for sample code that creates a System Tray icon for an application and when you right click on the system tray icon it will display a context menu with a list of options. Please could someone help me create a the basics of it.
Thank you.Andrew McIntyre
|
|
|
|
|
|
That link is no use to me. I only has links to magazines. Andrew McIntyre
|
|
|
|
|
Sorry about that. I have not visited that site for a long time.
Maybe you need to write your own code for that.
|
|
|
|
|
In fact, Paul DiLascia's sample program is available from Microsoft's website:
http://www.microsoft.com/msj/0299/c/c0299.aspx[^]
Click on the link at "code for this article", you will be able to download a ready to use code for tray icon manipulations. The second question in that article is about tray icons.
|
|
|
|
|
|
See here. The article itself is not about this topic, but the code is downloadable and easy to understand."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
|
|
|
|
|
Quite a few articles here on CodeProject; always the best place to search first. txtspeak is the realm of 9 year old children, not developers. Christian Graus
|
|
|
|
|
I was reading on the microsoft website how to encode a string of char [], this is my output:
#include "stdafx.h"
#include <conio.h>
#include <iostream>
#include <string>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
char EncString[] = "My name is Branden";
char key = 128;
cout << "Your string of text: " << EncString << endl;
for ( int i = 0 ; i < strlen(EncString) ; i++ )
EncString[i] = EncString[i] ^ key;
cout << "Encoded text : " << EncString << endl;
for ( int i = 0 ; i < strlen(EncString) ; i++ )
EncString[i] = EncString[i] ^ key;
cout << "Decoded text : " << EncString << endl;
_getch();
return 0;
}
I dont understand what '^' is, I know i have key declared as 128bits i guess, but the ^ operator throws me off. What is ^ specific function?
|
|
|
|
|
|
Herboren wrote: I dont understand what '^' is,
It's bitwise XOR operator
|
|
|
|
|
this is what i understand, it compares each bit of its first operand to the corresponding bit of the second operand.
but when I change the value of "key" from say 128 to 8, it comes out a totally different encoded string, why is that?
|
|
|
|
|
Encode 0x20 using Key 00000001:
0x20 = 0010 0000 XOR 00000001 = 00100001
to deccode do the XOR again:
00100001 XOR 00000001 = 0010 0000
But change key from 00000001 to 10000000 and you get:
0x20 = 0010 0000 XOR 10000000 = 10100000
to decode do the XOR again:
10100000 XOR 10000000 = 0010 0000
So a different Key gives a different encoded value but decodes using the same key to the original value.
|
|
|
|
|
So its just matching The string to a mixed ascii string and saving the key sequence for remembering it later.
|
|
|
|
|
Okay well i have another program that I just made and im still trying to figure out how this progam is getting the binary conversion:
#include "stdafx.h"
#include <conio.h>
using namespace std;
void Show_Binary(unsigned int u);
int _tmain(int argc, _TCHAR* argv[])
{
int i;
cout << "Enter a number between 1 - 255: "; cin >> i;
cout << "Your number in BINARY is : "; Show_Binary(i);
_getch();
return 0;
}
void Show_Binary(unsigned int u)
{
int t;
for ( t = 128; t > 0; t = t / 2 )
if (u & t) cout << "1 "; else
cout << "0 ";
cout << endl;
}
as u can see I have been trying to figure it out myself in the comment below, but the 't = t / 2' is throwing me off, I understand the t = 128, using the binary scale: 128 64 32 16 8 4 2 1, but how its checking it, is whats confusing me, I understand the if statements but when if just sits there with the 'if ( u & t)' im asking myself "wtf is if asking, is it equal to, is it less than more than dammit 'if' tell me what your evil plot is!" lol
|
|
|
|
|
It is trying to extract each bit out and show it on screen. In the language, the number 0 is understood as 'false', the number 1 is understood as 'true'. Hope you get the idea.
|
|
|
|
|
Ok so its extracting the bit itself, like 8bits equals =1byte sort of thing and each bit within those 8bits dont match it comes out as false otherwise true and its not matching the actual value that the user input
True>
User input: 2
Binary: 0000010
Match: 00000010
128 64 32 16 8 4 2 1
False False False False False False True False
correct?
False>
128 64 32 16 8 4 2 1
2
incorrectmodified on Thursday, March 11, 2010 3:54 PM
|
|
|
|
|
What a mess!
The key is for you to remember so you can decode an encoded text to get the original text. Different keys will produce different encoded text. For somebody who don't know the key you used to encode a string, he will have a hard time (not very hard for your algorithm, though) to decode to get the original text.
|
|
|
|
|
So if this were a GUI app asking for a certain to decode txt, he/she would need that key, I see thats actually really cool, I like how that works, arent there popular programs like that required user specific keys to decode the text?
|
|
|
|
|
'Matching' is a bit of a vague term to use, it's XORing each character of the string in turn with the key
for ( int i = 0 ; i < strlen(EncString) ; i++ )
EncString[i] = EncString[i] ^ key;
and replacing the character EncString[i] with the encoded character EncString[i] ^ key .
|
|
|
|
|
for ( int i = 0 ; i < strlen(EncString) ; i++ )
EncString[i] = EncString[i] ^ key;
I gotcha this is how I knew
char EncString[] = "My String of text";
Your string of text: My String of text
Encoded text : ═∙á╙⌠≥Θετá∩µá⌠σ°⌠
Decoded text : My String of text
char EncString[] = "My ";
Your string of text: My
Encoded text : ═∙á
Decoded text : My
'═∙á' match as long as the key bit stayed the same unless I changed its value
|
|
|
|