Implementing connection point callbacks from a different thread 
Author Message
 Implementing connection point callbacks from a different thread

I know you can't use the built in VC support for COM events to fire them
from a thread other then the one that originally called Advise() because the
IDispatch*s aren't marshalled for the proper thread (VB client).

I'm thinking about replacing the CComDynamicUnkArray used by default in the
IConnectionPointImpl template, which the event proxy VC generates inherits
from, with a version the stores the IUnk*s in the GIT.

CComDynamicMarshalledUnkArray?

If everything works as planned, I should have a nice generic little class
that I can reuse and just plug in whenever I want to do this again.

Does anyone initially see a problem with this approach?

I gave it a first shot and I get "... value of ESP not properly saved ..."
when I make the IDisp* to the event, even though it appears everything has
gone fine (i.e. HR's are all ok).  Of course this could just be a bug...?



Fri, 07 Mar 2003 03:00:00 GMT  
 Implementing connection point callbacks from a different thread

Quote:
> I know you can't use the built in VC support for COM events to fire them
> from a thread other then the one that originally called Advise() because
the
> IDispatch*s aren't marshalled for the proper thread (VB client).

I was able to marshal accross to worker thread and fire events back to
all my clients, VB, VC MFC, VC exe's.

As for the idea you have present, I haven't reached that understanding yet
;)



Fri, 07 Mar 2003 03:00:00 GMT  
 Implementing connection point callbacks from a different thread

Sounds like an interesting and promising avenue.
I have been using PostMessage from the other thread, with a message in the
WM_APP range, to send the address of a "new"-ed structure to the main
thread.
The main thread then fires the necessary events.
What is your reason not to use this coward's way out?


Quote:
> I know you can't use the built in VC support for COM events to fire them
> from a thread other then the one that originally called Advise() because
the
> IDispatch*s aren't marshalled for the proper thread (VB client).

> I'm thinking about replacing the CComDynamicUnkArray used by default in
the
> IConnectionPointImpl template, which the event proxy VC generates inherits
> from, with a version the stores the IUnk*s in the GIT.

> CComDynamicMarshalledUnkArray?

> If everything works as planned, I should have a nice generic little class
> that I can reuse and just plug in whenever I want to do this again.

> Does anyone initially see a problem with this approach?

> I gave it a first shot and I get "... value of ESP not properly saved ..."
> when I make the IDisp* to the event, even though it appears everything has
> gone fine (i.e. HR's are all ok).  Of course this could just be a bug...?



Sat, 08 Mar 2003 03:00:00 GMT  
 Implementing connection point callbacks from a different thread

How did you marshal the IDisp from the firing thread?

Refering to the code below (from the CP proxy  implementation)

m_vec is just a glorified CSimpleArray and when Adive is called on the CP a
IUnk* is stored in the array.  At line 4 the pointer is reterived by the
firing thread, which is different from the thread that the IUnk* was
originally marshalled for (the STA vb client main thread).  The invoke call
at line 10 will fail w/a 'pointer not marshelled for this thread' error.

How did you late marshal the pointer?
I usually just use CoMarshalInterThreadInterfaceInStream, but that would
have to be done in the advise and then you'd only get one event to fire
becuase the IStream produced is only good for one unmarshalling.  That's why
I want to use the GIT.

Anyhow, how did you get around this problem?

1  int nConnections = m_vec.GetSize();

2  for (nConnectionIndex = 0; nConnectionIndex < nConnections;
nConnectionIndex++)
  {
3   pT->Lock();
4   CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
5   pT->Unlock();

6   IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
7   if (pDispatch != NULL)
   {
8    pvars[0] = SomeNumber;
9    DISPPARAMS disp = { pvars, NULL, 1, 0 };
10    pDispatch->Invoke(...


Quote:
> > I know you can't use the built in VC support for COM events to fire them
> > from a thread other then the one that originally called Advise() because
> the
> > IDispatch*s aren't marshalled for the proper thread (VB client).

> I was able to marshal accross to worker thread and fire events back to
> all my clients, VB, VC MFC, VC exe's.

> As for the idea you have present, I haven't reached that understanding yet
> ;)



Sat, 08 Mar 2003 03:00:00 GMT  
 Implementing connection point callbacks from a different thread

I've see that done before.

As for why I'm not looking at that, 3 reasons:

1. It's the cowards way out

2. The CComDynamicMarshalledUnkArray would mean I could just plug exactly
the same class into any project I wanted and it would just work w/out any
extra coding at all

3. VB client, don't want to implement message loop in VB.  The message based
implementation I saw actually created a new window on the advise side of
things and it's WinProc took care of the extra message and firing the event.
But that's messy and requires more work to plugin to new projects then a
slick little class

Quote:

> Sounds like an interesting and promising avenue.
> I have been using PostMessage from the other thread, with a message in the
> WM_APP range, to send the address of a "new"-ed structure to the main
> thread.
> The main thread then fires the necessary events.
> What is your reason not to use this coward's way out?



> > I know you can't use the built in VC support for COM events to fire them
> > from a thread other then the one that originally called Advise() because
> the
> > IDispatch*s aren't marshalled for the proper thread (VB client).

> > I'm thinking about replacing the CComDynamicUnkArray used by default in
> the
> > IConnectionPointImpl template, which the event proxy VC generates
inherits
> > from, with a version the stores the IUnk*s in the GIT.

> > CComDynamicMarshalledUnkArray?

> > If everything works as planned, I should have a nice generic little
class
> > that I can reuse and just plug in whenever I want to do this again.

> > Does anyone initially see a problem with this approach?

> > I gave it a first shot and I get "... value of ESP not properly saved
..."
> > when I make the IDisp* to the event, even though it appears everything
has
> > gone fine (i.e. HR's are all ok).  Of course this could just be a
bug...?



Sat, 08 Mar 2003 03:00:00 GMT  
 Implementing connection point callbacks from a different thread

See inline.

--
=====================================
Alexander Nickolov
Microsoft MVP [VC], MCSD

MVP VC FAQ: http://www.mvps.org/vcfaq
=====================================


Quote:
> I've see that done before.

> As for why I'm not looking at that, 3 reasons:

> 1. It's the cowards way out

No - it's more elegant because your worker thread is not stuck waiting for
the
client to process the event.

Quote:

> 2. The CComDynamicMarshalledUnkArray would mean I could just plug exactly
> the same class into any project I wanted and it would just work w/out any
> extra coding at all

That's nice, but it is impossible. You need to modify the proxy code every
time...

Quote:

> 3. VB client, don't want to implement message loop in VB.  The message
based
> implementation I saw actually created a new window on the advise side of
> things and it's WinProc took care of the extra message and firing the
event.
> But that's messy and requires more work to plugin to new projects then a
> slick little class

You don't care about the message loop, because either the client or COM is
going to provide it as long as your component has ThreadingModel=Apartment.

Quote:


> > Sounds like an interesting and promising avenue.
> > I have been using PostMessage from the other thread, with a message in
the
> > WM_APP range, to send the address of a "new"-ed structure to the main
> > thread.
> > The main thread then fires the necessary events.
> > What is your reason not to use this coward's way out?



> > > I know you can't use the built in VC support for COM events to fire
them
> > > from a thread other then the one that originally called Advise()
because
> > the
> > > IDispatch*s aren't marshalled for the proper thread (VB client).

> > > I'm thinking about replacing the CComDynamicUnkArray used by default
in
> > the
> > > IConnectionPointImpl template, which the event proxy VC generates
> inherits
> > > from, with a version the stores the IUnk*s in the GIT.

> > > CComDynamicMarshalledUnkArray?

> > > If everything works as planned, I should have a nice generic little
> class
> > > that I can reuse and just plug in whenever I want to do this again.

> > > Does anyone initially see a problem with this approach?

> > > I gave it a first shot and I get "... value of ESP not properly saved
> ..."
> > > when I make the IDisp* to the event, even though it appears everything
> has
> > > gone fine (i.e. HR's are all ok).  Of course this could just be a
> bug...?



Sat, 08 Mar 2003 03:00:00 GMT  
 Implementing connection point callbacks from a different thread

Yes. The unknown array doesn't know the type of the interface it marshals.
See this exerpt from IConnectionPointImpl::Advise:

  *pdwCookie = m_vec.Add(p);

This is not so big a problem - we can store IUnknown pointers. However,
when we return the pointers back to the proxy code, it assumes the pointer
is indeed the corresponding CP interface. You'll have to modify the proxy
code to take care of that. Also, keep in mind that the pointer returned from
m_vec.GetAt() is _not_ AddRef-ed, so you have to change the definition
to return CComPtr<IUnknown> instead - so as not to leak a reference on
each event fired...

Shortly, it is _impossible_ to do what you want... If it were possible, I
long since would have built such a class...

One compromise you can do (and only for dispinterface-based events) is
to hard-code IDispatch for the type. Note explicitly in the documentation
that it must only be used with dispinterfaces! This class can be built!
To be honest, I just thought this up - haven't even tried it myself, but my
intuition tells me it's doable... Well, I rarely use dispinterfaces, so I
haven't thought about this before... Maybe another article in the FAQ...
(Do you mind? I don't get credit for that, so I have no idea how to give
you credit either...)

--
=====================================
Alexander Nickolov
Microsoft MVP [VC], MCSD

MVP VC FAQ: http://www.mvps.org/vcfaq
=====================================


Quote:
> I know you can't use the built in VC support for COM events to fire them
> from a thread other then the one that originally called Advise() because
the
> IDispatch*s aren't marshalled for the proper thread (VB client).

> I'm thinking about replacing the CComDynamicUnkArray used by default in
the
> IConnectionPointImpl template, which the event proxy VC generates inherits
> from, with a version the stores the IUnk*s in the GIT.

> CComDynamicMarshalledUnkArray?

> If everything works as planned, I should have a nice generic little class
> that I can reuse and just plug in whenever I want to do this again.

> Does anyone initially see a problem with this approach?

> I gave it a first shot and I get "... value of ESP not properly saved ..."
> when I make the IDisp* to the event, even though it appears everything has
> gone fine (i.e. HR's are all ok).  Of course this could just be a bug...?



Sat, 08 Mar 2003 03:00:00 GMT  
 Implementing connection point callbacks from a different thread

I gave is a shot earlier, using a CSimpleMap to store the GIT Token keyed by
the IUnk* from the advise (via the Add method).  This leaves most of the
existing processing alone and keeps the original IUnk* array there in case
anyone expects it.  The GetInterfaceFromGlobal call does an AddRef
internally so I don't have to take care of that.

I encountered that ESP error again, however QI'ing the interface returned
(CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);) for an IDisp* and
getting rid of the type cast works fine.  That goes against my idea of just
plugging in the new class, but c'est la vie.

I don't know why QI'ing for the IDisp* works, so if you do let me know.  It
probably has something to do with angering the proxy.

And ya, anyone using the pointers from the enumerators from a different
thread (i.e. begin & end) for anything other than running through the array
is going to run into serious problems.

Thanks for the code.  I'll take a closer look.


Quote:
> Yes. The unknown array doesn't know the type of the interface it marshals.
> See this exerpt from IConnectionPointImpl::Advise:

>   *pdwCookie = m_vec.Add(p);

> This is not so big a problem - we can store IUnknown pointers. However,
> when we return the pointers back to the proxy code, it assumes the pointer
> is indeed the corresponding CP interface. You'll have to modify the proxy
> code to take care of that. Also, keep in mind that the pointer returned
from
> m_vec.GetAt() is _not_ AddRef-ed, so you have to change the definition
> to return CComPtr<IUnknown> instead - so as not to leak a reference on
> each event fired...

> Shortly, it is _impossible_ to do what you want... If it were possible, I
> long since would have built such a class...

> One compromise you can do (and only for dispinterface-based events) is
> to hard-code IDispatch for the type. Note explicitly in the documentation
> that it must only be used with dispinterfaces! This class can be built!
> To be honest, I just thought this up - haven't even tried it myself, but
my
> intuition tells me it's doable... Well, I rarely use dispinterfaces, so I
> haven't thought about this before... Maybe another article in the FAQ...
> (Do you mind? I don't get credit for that, so I have no idea how to give
> you credit either...)

> --
> =====================================
> Alexander Nickolov
> Microsoft MVP [VC], MCSD

> MVP VC FAQ: http://www.mvps.org/vcfaq
> =====================================



> > I know you can't use the built in VC support for COM events to fire them
> > from a thread other then the one that originally called Advise() because
> the
> > IDispatch*s aren't marshalled for the proper thread (VB client).

> > I'm thinking about replacing the CComDynamicUnkArray used by default in
> the
> > IConnectionPointImpl template, which the event proxy VC generates
inherits
> > from, with a version the stores the IUnk*s in the GIT.

> > CComDynamicMarshalledUnkArray?

> > If everything works as planned, I should have a nice generic little
class
> > that I can reuse and just plug in whenever I want to do this again.

> > Does anyone initially see a problem with this approach?

> > I gave it a first shot and I get "... value of ESP not properly saved
..."
> > when I make the IDisp* to the event, even though it appears everything
has
> > gone fine (i.e. HR's are all ok).  Of course this could just be a
bug...?



Sat, 08 Mar 2003 03:00:00 GMT  
 Implementing connection point callbacks from a different thread
Hi,

see http://codeguru.earthweb.com/atl/ThreadEvents.shtml

you must only include following statements in CEventProxy.h

using namespace std;

Michael


Quote:

> I know you can't use the built in VC support for COM events to fire them
> from a thread other then the one that originally called Advise() because the
> IDispatch*s aren't marshalled for the proper thread (VB client).

> I'm thinking about replacing the CComDynamicUnkArray used by default in the
> IConnectionPointImpl template, which the event proxy VC generates inherits
> from, with a version the stores the IUnk*s in the GIT.

> CComDynamicMarshalledUnkArray?

> If everything works as planned, I should have a nice generic little class
> that I can reuse and just plug in whenever I want to do this again.

> Does anyone initially see a problem with this approach?

> I gave it a first shot and I get "... value of ESP not properly saved ..."
> when I make the IDisp* to the event, even though it appears everything has
> gone fine (i.e. HR's are all ok).  Of course this could just be a bug...?



Sun, 09 Mar 2003 12:37:47 GMT  
 Implementing connection point callbacks from a different thread

Forget it. It's ugly. It has a bug leaking references. And I don't like it
at all... Some more free time and I'll write a proper solution to replace
IConnecttionPointImpl as well...

--
=====================================
Alexander Nickolov
Microsoft MVP [VC], MCSD

MVP VC FAQ: http://www.mvps.org/vcfaq
=====================================


Quote:
> Here's the first version I came up with. Not tested! You have to include
> the file in StdAfx.h and modify the proxy class to use this class instead
of
> CComDynamicUnkArray as the last parameter to IConnectionPointImpl.

> WARNING!!! IConnectionPoint::EnumConnections doesn't work!!!
> Due to some necessary hacks...

> IMO, a clean solution is not replacing CComDynamicUnkArray only, but
> replacing IConnectionPointImpl as well...

> --
> =====================================
> Alexander Nickolov
> Microsoft MVP [VC], MCSD

> MVP VC FAQ: http://www.mvps.org/vcfaq
> =====================================



> > Yes. The unknown array doesn't know the type of the interface it
marshals.
> > See this exerpt from IConnectionPointImpl::Advise:

> >   *pdwCookie = m_vec.Add(p);

> > This is not so big a problem - we can store IUnknown pointers. However,
> > when we return the pointers back to the proxy code, it assumes the
pointer
> > is indeed the corresponding CP interface. You'll have to modify the
proxy
> > code to take care of that. Also, keep in mind that the pointer returned
> from
> > m_vec.GetAt() is _not_ AddRef-ed, so you have to change the definition
> > to return CComPtr<IUnknown> instead - so as not to leak a reference on
> > each event fired...

> > Shortly, it is _impossible_ to do what you want... If it were possible,
I
> > long since would have built such a class...

> > One compromise you can do (and only for dispinterface-based events) is
> > to hard-code IDispatch for the type. Note explicitly in the
documentation
> > that it must only be used with dispinterfaces! This class can be built!
> > To be honest, I just thought this up - haven't even tried it myself, but
> my
> > intuition tells me it's doable... Well, I rarely use dispinterfaces, so
I
> > haven't thought about this before... Maybe another article in the FAQ...
> > (Do you mind? I don't get credit for that, so I have no idea how to give
> > you credit either...)

> > --
> > =====================================
> > Alexander Nickolov
> > Microsoft MVP [VC], MCSD

> > MVP VC FAQ: http://www.mvps.org/vcfaq
> > =====================================



> > > I know you can't use the built in VC support for COM events to fire
them
> > > from a thread other then the one that originally called Advise()
because
> > the
> > > IDispatch*s aren't marshalled for the proper thread (VB client).

> > > I'm thinking about replacing the CComDynamicUnkArray used by default
in
> > the
> > > IConnectionPointImpl template, which the event proxy VC generates
> inherits
> > > from, with a version the stores the IUnk*s in the GIT.

> > > CComDynamicMarshalledUnkArray?

> > > If everything works as planned, I should have a nice generic little
> class
> > > that I can reuse and just plug in whenever I want to do this again.

> > > Does anyone initially see a problem with this approach?

> > > I gave it a first shot and I get "... value of ESP not properly saved
> ..."
> > > when I make the IDisp* to the event, even though it appears everything
> has
> > > gone fine (i.e. HR's are all ok).  Of course this could just be a
> bug...?



Sun, 09 Mar 2003 03:00:00 GMT  
 Implementing connection point callbacks from a different thread

Thanks, that's basically exactly what I wrote (only it was done 2 months
earlier, you get the patent).

I'm not detecting any leaks, do you know what Alexander Nickolov is talking
about?


Quote:
> Hi,

> see http://codeguru.earthweb.com/atl/ThreadEvents.shtml

> you must only include following statements in CEventProxy.h

> using namespace std;

> Michael



> > I know you can't use the built in VC support for COM events to fire them
> > from a thread other then the one that originally called Advise() because
the
> > IDispatch*s aren't marshalled for the proper thread (VB client).

> > I'm thinking about replacing the CComDynamicUnkArray used by default in
the
> > IConnectionPointImpl template, which the event proxy VC generates
inherits
> > from, with a version the stores the IUnk*s in the GIT.

> > CComDynamicMarshalledUnkArray?

> > If everything works as planned, I should have a nice generic little
class
> > that I can reuse and just plug in whenever I want to do this again.

> > Does anyone initially see a problem with this approach?

> > I gave it a first shot and I get "... value of ESP not properly saved
..."
> > when I make the IDisp* to the event, even though it appears everything
has
> > gone fine (i.e. HR's are all ok).  Of course this could just be a
bug...?



Sun, 09 Mar 2003 03:00:00 GMT  
 Implementing connection point callbacks from a different thread
Hi,

Quote:
> I'm not detecting any leaks, do you know what Alexander Nickolov is talking
> about?

No !?

Michael



Mon, 10 Mar 2003 03:00:00 GMT  
 
 [ 12 post ] 

 Relevant Pages 

1. Deleting a valid allocated memory hangs the connection point Callback thread

2. Connection points in different threads

3. Connection points in different threads

4. how to fire a connection point from callback routine

5. No Implement Connection Point in ATL7

6. trouble implementing connection points

7. use ATL Wizard implement broadcast connection point

8. Implement Connection Point wizard code bogus?

9. Implementing connection points

10. Implementing Connection Point without the IDE

11. "Implement Connection Point..." option is missing

12. EVC4: ATL Implement Connection Point

 

 
Powered by phpBB® Forum Software