Click here to Skip to main content
15,911,039 members
Home / Discussions / COM
   

COM

 
GeneralRe: Event handing problem. Pin
Lim Bio Liong26-Jan-04 20:17
Lim Bio Liong26-Jan-04 20:17 
GeneralRe: Event handing problem. Pin
Prakash Nadar27-Jan-04 5:07
Prakash Nadar27-Jan-04 5:07 
GeneralRe: Event handing problem. Pin
Maverick3-Feb-04 20:03
Maverick3-Feb-04 20:03 
GeneralRe: Event handing problem. Pin
Lim Bio Liong4-Feb-04 7:01
Lim Bio Liong4-Feb-04 7:01 
GeneralRe: Event handing problem. Pin
Maverick4-Feb-04 15:54
Maverick4-Feb-04 15:54 
GeneralRe: Event handing problem. Pin
Lim Bio Liong4-Feb-04 17:17
Lim Bio Liong4-Feb-04 17:17 
GeneralRe: Event handing problem. Pin
Lim Bio Liong4-Feb-04 19:49
Lim Bio Liong4-Feb-04 19:49 
GeneralRe: Event handing problem. Pin
Lim Bio Liong4-Feb-04 20:22
Lim Bio Liong4-Feb-04 20:22 
Hello Maverick,

We'll continue with part two of our discussion :

11. How do we resolve the problems ? In short, we must marshall VB's Event dispinterface so that when MyNetworkClass::OnRequestConnection() is called, the dispinterface is ready to be used. The following is a summary of how we can achieve this :

11.1 In the MyNetworkClass C++ class, create 2 STL vectors :

typedef vector<LPSTREAM> ISTREAM_VECTOR;
typedef vector<LPDISPATCH> IDISPATCH_VECTOR;

ISTREAM_VECTOR m_vectorStream;
IDISPATCH_VECTOR m_vectorDispatch;

The first vector is used to hold IStream pointers. When COM marshalls interface pointers, it uses IStreams to temporarily hold interface data. The same IStreams are used to unmarshall interface pointers in destination threads.

The second vector is used to hold IDispatch pointers. Each IDispatch pointer points to a dispinterface of a VB Event Object.

11.2 In the MyNetworkClass C++ class, instead of internally holding a pointer to an interface of your ATL COM Object, hold a pointer to the C++ class that implements the ATL COM Object, e.g. :

instead of :
IMyCOMObjectInterfacePtr m_spIMyCOMObjectInterface;

or
IMyCOMObjectInterface* m_pIMyCOMObjectInterface;

use :

CMyCOMObject* m_pCMyCOMObject;

11.3 In the MyNetworkClass C++ class, create a function like the following :

long MyNetworkClass::MarshalEventDispatchInterfaces ()
{
int nConnections = (m_pCMyCOMObject -> m_vec).GetSize();
int nConnectionIndex = 0;
HRESULT hrTemp = S_OK;
long lRet = 0;

for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
{
IStream* pIStreamTemp = NULL;

m_pCMyCOMObject -> Lock();
CComPtr<IUnknown> sp = (m_pCMyCOMObject -> m_vec).GetAt(nConnectionIndex);
m_pCMyCOMObject -> Unlock();

IDispatch* pIDispatchTemp = reinterpret_cast<IDispatch*>(sp.p);

if (pIDispatchTemp)
{
// Create stream for marshaling IDispatch to search thread.
hrTemp = ::CoMarshalInterThreadInterfaceInStream
(
IID_IDispatch, // interface ID to marshal
pIDispatchTemp, // ptr to interface to marshal
&pIStreamTemp // output variable
);

// Place stream in member variable where COM thread will look for it.
// No need to call Release() on pStream. They will be Release()'d
// when we later call CoGetInterfaceAndReleaseStream().
if (pIStreamTemp)
{
m_vectorStream.push_back(pIStreamTemp);
}

// Also no need to call pIDispatchTemp->Release(). pIDispatchTemp is a temporary pointer
// to the IUnknown pointer in sp. And sp will automatically call Release() on its
// internal IUnknown pointer.
}
}

return lRet;
}

This function iterates through the connection points contained in the connection points vector (m_vec) of the COM Object. Note that a COM Object can be connected to more than one connection point.

Each connection point is an implementation of a specific event set. If your COM Object only implements one event set, then each connection point is of the same dispinterface.

We get each connection point, cast it into an IDispatch pointer and then call the Win32 API CoMarshalInterThreadInterfaceInStream() on it. The CoMarshalInterThreadInterfaceInStream() function will take the IDispatch pointer and create an IStream object that stores data pertaining the the IDispatch interface pointer. We then store the output IStream pointer into our stream vector m_vectorStream.

Call this function early, e.g. when your COM Object is first created or before you call the Network SDK function that start the thread. The idea is to prepare the dispinterfaces for marshalling into the Network SDK thread.


11.4 In the MyNetworkClass C++ class, create another function like the following :

long MyNetworkClass::UnMarshallEventDispatchInterfaces ()
{
ISTREAM_VECTOR::iterator theIterator;
int iIndex = 0;
HRESULT hrTemp = S_OK;
long lRet = 0;

// Unmarshal interface pointers
for (theIterator = m_vectorStream.begin(); theIterator != m_vectorStream.end(); theIterator++)
{
IDispatch* pIDispatchTemp = NULL;
IStream* pIStreamTemp = NULL;

// Get stream pointer.
pIStreamTemp = (*theIterator);

if (pIStreamTemp)
{
// Use stream pointer to create IDispatch pointer that we can call from this thread.
hrTemp = ::CoGetInterfaceAndReleaseStream
(
pIStreamTemp, // stream containing marshaling info
IID_IDispatch, // interface desired
(void**)&pIDispatchTemp // output variable
);

// Note that at this time, pIStreamTemp will be Release()'d and will no longer
// be valid.

// Put resulting IDispatch pointer in IDispatch pointers vector.
if (pIDispatchTemp)
{
m_vectorDispatch.push_back(pIDispatchTemp);
pIDispatchTemp -> AddRef(); // Since we have added pIDispatchTemp into a collection, we have an additional reference to it.
}
}
}

return lRet;
}

This function iterates through each IStream pointer stored in MyNetworkClass::m_vectorStream and uses it in a call to the Win32 API CoGetInterfaceAndReleaseStream().

This call will return to us a pointer to our IDispatch pointer from the IStream object.

After obtaining this IDispatch pointer, we will store it into our IDispatch vector m_vectorDispatch.

Call this function in the MyNetworkClass::OnRequestConnection() function. But call it only once so that the IDispatch vector is filled up only one time. After calling this function, we can invoke the specific event of your event set (by calling the IDispatch::Invoke() method).


11.5 We invoke the specific event by iterating through the IDispatch pointers contained in the IDispatch vector :

HRESULT FireEvent()
{
IDISPATCH_VECTOR::iterator theIterator;
int iIndex = 0;
CComVariant varResult;
CComVariant* pvars = new CComVariant[1];
HRESULT hrRet = S_OK;

for (theIterator = m_vectorDispatch.begin(); theIterator != m_vectorDispatch.end(); theIterator++)
{
IDispatch* pIDispatch = (*theIterator);

if (pIDispatch)
{
VariantClear(&varResult);
pvars[0] = 100;
DISPPARAMS disp = { pvars, NULL, 1, 0 };
pIDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
}
}

delete[] pvars;

hrRet = varResult.scode;

return hrRet;
}

The above function is an example of invoking an event that takes a long parameter (value 100).


Modify the above examples to suit your particular case, Maverick. Contact me again if you need further clarifications. Please note that my examples are for illustration purposes. I have emphasised on principles and have not paid attention to details like syntax errors or memory considerations.

You will, of course need to do things like clearing the vectors and ensuring that the functions MarshalEventDispatchInterfaces() and UnMarshallEventDispatchInterfaces() are called appropriately at the right time and place.

Best of luck, Maverick,
Bio.









GeneralRe: Event handing problem. Pin
Maverick4-Feb-04 20:57
Maverick4-Feb-04 20:57 
GeneralRe: Event handing problem. Pin
Lim Bio Liong4-Feb-04 23:39
Lim Bio Liong4-Feb-04 23:39 
GeneralRe: Event handing problem. Pin
Maverick5-Feb-04 0:31
Maverick5-Feb-04 0:31 
GeneralRe: Event handing problem. Pin
Lim Bio Liong5-Feb-04 0:48
Lim Bio Liong5-Feb-04 0:48 
GeneralRe: Event handing problem. Pin
Maverick5-Feb-04 15:42
Maverick5-Feb-04 15:42 
GeneralRe: Event handing problem. Pin
Lim Bio Liong6-Feb-04 1:27
Lim Bio Liong6-Feb-04 1:27 
GeneralReg: EnumConnectionPoints and IEnumConnectionPoints Pin
Adi Narayana20-Jan-04 4:07
Adi Narayana20-Jan-04 4:07 
GeneralRe: Reg: EnumConnectionPoints and IEnumConnectionPoints Pin
Jörgen Sigvardsson25-Jan-04 13:45
Jörgen Sigvardsson25-Jan-04 13:45 
GeneralStructured storage and compound files Pin
Omar Alvi20-Jan-04 2:04
Omar Alvi20-Jan-04 2:04 
GeneralRe: Structured storage and compound files Pin
Jörgen Sigvardsson25-Jan-04 13:49
Jörgen Sigvardsson25-Jan-04 13:49 
GeneralIProcessInitializer / COM+ Pin
vlvl19-Jan-04 4:58
vlvl19-Jan-04 4:58 
GeneralI need a good book... Pin
profoundwhispers19-Jan-04 3:17
profoundwhispers19-Jan-04 3:17 
GeneralRe: I need a good book... Pin
Jörgen Sigvardsson25-Jan-04 13:54
Jörgen Sigvardsson25-Jan-04 13:54 
GeneralRe: I need a good book... Pin
Prakash Nadar25-Jan-04 22:17
Prakash Nadar25-Jan-04 22:17 
GeneralRe: I need a good book... Pin
Jörgen Sigvardsson25-Jan-04 22:21
Jörgen Sigvardsson25-Jan-04 22:21 
GeneralScriptable ActiveX and javascript Pin
gialli19-Jan-04 2:04
gialli19-Jan-04 2:04 
GeneralRe: Scriptable ActiveX and javascript Pin
Anonymous30-Jan-04 10:54
Anonymous30-Jan-04 10:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.