Implementing connection point callbacks from a different thread
Author |
Message |
Kris Lan #1 / 12
|
 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 |
|
 |
msnews.microsoft.co #2 / 12
|
 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 |
|
 |
Fred Jackso #3 / 12
|
 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 |
|
 |
Kris Lan #4 / 12
|
 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 |
|
 |
Kris Lan #5 / 12
|
 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 |
|
 |
Alexander Nickolo #6 / 12
|
 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 |
|
 |
Alexander Nickolo #7 / 12
|
 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 |
|
 |
Kris Lan #8 / 12
|
 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 |
|
 |
Michael Lindi #9 / 12
|
 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 |
|
 |
Alexander Nickolo #10 / 12
|
 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 |
|
 |
Kris Lan #11 / 12
|
 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 |
|
 |
Michael Lindi #12 / 12
|
 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 |
|
|
|