- ccomthread_src.zip
- LegacyCOMObject1
- Shared
- SimpleCOMObject1
- SimpleCOMObject2
- Test Programs
- VBTest
- VCTests
- DemonstrateDefaultSTA
- VCTest01
- main.cpp
- SimpleCOMObject2.tlh
- SimpleCOMObject2.tli
- VCTest01.dsp
- VCTest01.dsw
- VCTest02
- main.cpp
- SimpleCOMObject2.tlh
- SimpleCOMObject2.tli
- VCTest02.dsp
- VCTest02.dsw
- DemonstrateExeServerSTA
- Client
- VCTest01
- Implementation
- ExeServerImpl
- Interface
- ExeServerInterfaces
- DemonstrateLegacySTA
- VCTest01
- LegacyCOMObject1.tlh
- LegacyCOMObject1.tli
- main.cpp
- VCTest01.dsp
- VCTest01.dsw
- VCTest02
- DemonstrateNoMessageLoop
- VCTest01
- main.cpp
- SimpleCOMObject2.tlh
- SimpleCOMObject2.tli
- VCTest01.dsp
- VCTest01.dsw
- DemonstrateSTA
- VCTest01
- main.cpp
- SimpleCOMObject2.tlh
- SimpleCOMObject2.tli
- VCTest01.dsp
- VCTest01.dsw
|
// SimpleCOMObject1_impl.cpp : Implementation of CSimpleCOMObject1
#include "stdafx.h"
#include "SimpleCOMObject1.h"
#include "SimpleCOMObject1_impl.h"
/////////////////////////////////////////////////////////////////////////////
// CSimpleCOMObject1
// Remember that in a COM Thread, always use CoTaskMemAlloc() and CoTaskMemFree()
// to allocate and de-allocate memory.
DWORD WINAPI ThreadFunc_ComThread(LPVOID lpThreadParameter)
{
CComThread* pCComThread = (CComThread*)lpThreadParameter;
CSimpleCOMObject1* pCSimpleCOMObject1 = (CSimpleCOMObject1*)(pCComThread -> GetThreadParam());
HANDLE dwChangeHandles[2];
bool bContinueLoop = true;
IUNKNOWN_VECTOR theVector;
IUNKNOWN_VECTOR::iterator theIterator;
_ISimpleCOMObject1Events* p_ISimpleCOMObject1Events = NULL;
DWORD dwWaitStatus = 0;
DWORD dwRet = 0;
dwChangeHandles[0] = pCSimpleCOMObject1 -> m_hExitThread;
dwChangeHandles[1] = pCSimpleCOMObject1 -> m_hStartLengthyFunction;
// We go through the IUnknown pointers stored in pCComThread
// (by the object which called this thread) and search for
// a _ISimpleCOMObject1Events dispinterface pointer.
// If found, this _ISimpleCOMObject1Events dispinterface pointer
// is the event handler interface of the client that uses the CSimpleCOMObject1
// COM Object.
theVector = (IUNKNOWN_VECTOR&)(*pCComThread);
for (theIterator = theVector.begin(); theIterator != theVector.end(); theIterator++)
{
IUnknown* pIUnknownTemp = (*theIterator);
IDispatch* pIDispatch = NULL;
if (pIUnknownTemp)
{
pIUnknownTemp -> QueryInterface (IID_IDispatch, (void**)&pIDispatch);
}
if(pIDispatch)
{
pIDispatch -> QueryInterface(__uuidof(_ISimpleCOMObject1Events), (void**)&p_ISimpleCOMObject1Events);
pIDispatch -> Release();
pIDispatch = NULL;
if (p_ISimpleCOMObject1Events)
{
break;
}
}
}
// Note that p_ISimpleCOMObject1Events may be NULL.
// This will be so if the client does not wish to receive
// any event from the object.
// Msg Loop while waiting for thread to exit.
while (bContinueLoop)
{
// Wait for notification.
dwWaitStatus = ::MsgWaitForMultipleObjectsEx
(
(DWORD)2, // number of handles in array
dwChangeHandles, // object-handle array
(DWORD)INFINITE, // time-out interval
(DWORD)(QS_ALLINPUT | QS_ALLPOSTMESSAGE), // input-event type
(DWORD)(MWMO_INPUTAVAILABLE) // wait options
);
switch (dwWaitStatus)
{
// First wait (thread exit) object has been signalled.
case WAIT_OBJECT_0 :
{
// Flag to indicate stop loop.
bContinueLoop = false;
break;
}
// Second wait (do lengthy function) object has been signalled.
case WAIT_OBJECT_0 + 1:
{
// We must now perform the lengthy function.
// When capturing has completed, we fire the LengthyFunctionCompleted() event.
if (p_ISimpleCOMObject1Events)
{
IDispatch* pIDispatch = NULL;
p_ISimpleCOMObject1Events -> QueryInterface(&pIDispatch);
if (pIDispatch)
{
CComVariant varResult;
CComVariant* pvars = new CComVariant[1];
VariantClear(&varResult);
pvars[0] = (long)0;
DISPPARAMS disp = { pvars, NULL, 1, 0 };
pIDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
pIDispatch -> Release();
pIDispatch = NULL;
delete[] pvars;
}
}
ResetEvent(dwChangeHandles[1]);
break;
}
// Windows message has arrived.
case WAIT_OBJECT_0 + 2:
{
MSG msg;
// Dispatch all windows messages in queue.
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage (&msg);
DispatchMessage(&msg);
}
break;
}
default:
{
break;
}
}
}
if (p_ISimpleCOMObject1Events)
{
p_ISimpleCOMObject1Events -> Release();
p_ISimpleCOMObject1Events = NULL;
}
return dwRet;
}
STDMETHODIMP CSimpleCOMObject1::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* arr[] =
{
&IID_ISimpleCOMObject1
};
for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}
STDMETHODIMP CSimpleCOMObject1::Initialize()
{
// TODO: Add your implementation code here
InitializeComThread();
return S_OK;
}
STDMETHODIMP CSimpleCOMObject1::Uninitialize()
{
// TODO: Add your implementation code here
UninitializeComThread();
return S_OK;
}
STDMETHODIMP CSimpleCOMObject1::DoLengthyFunction(long lTimeout)
{
// TODO: Add your implementation code here
m_lLengthyFunctionTimeout = lTimeout;
if (m_hStartLengthyFunction)
{
SetEvent(m_hStartLengthyFunction);
}
return S_OK;
}
/* ***** InitializeComThread() will initialize the CComThread object ***** */
/* ***** m_COMThread and connect it with our thread function ThreadFunc_ComThread. ***** */
/* ***** We will also use m_COMThread to marshall CSimpleCOMObject1's sink pointers ***** */
/* ***** to the thread. ***** */
void CSimpleCOMObject1::InitializeComThread()
{
IUnknown* pIUnknown = NULL;
// Obtain this object's IUnknown pointer.
// This will be kept inside m_COMThread and will
// later be passed onto the ThreadFunc_ComThread thread.
this -> QueryInterface (IID_IUnknown, (void**)&pIUnknown);
if (pIUnknown)
{
// Tell m_COMThread not to start the thread function
// ThreadFunc_ComThread immedietaly. Tell it to
// suspend until the ThreadResume() function is called.
m_COMThread.SetFlags((CComThread::Flags)(CComThread::FLAG_START_SUSPENDED));
// Pass this object itself as a parameter to the thread
// function.
m_COMThread.SetThreadParam ((LPVOID)this);
m_COMThread.SetStartAddress (ThreadFunc_ComThread);
m_COMThread.AddUnknownPointer(pIUnknown);
// We marshall this object's sink pointers
// to the ThreadFunc_ComThread thread.
MarshalEventDispatchInterfacesToComThread();
m_COMThread.ThreadStart();
m_COMThread.ThreadResume();
pIUnknown -> Release();
pIUnknown = NULL;
}
}
void CSimpleCOMObject1::UninitializeComThread()
{
if (m_hExitThread)
{
SetEvent(m_hExitThread);
}
m_COMThread.WaitThreadStop();
}
/* ***** The pointers to this object's event sinks are kept in ***** */
/* ***** IConnectionPointImpl::m_vec which is an STL collection of ***** */
/* ***** CComPtr<IUnknown> objects. ***** */
void CSimpleCOMObject1::MarshalEventDispatchInterfacesToComThread()
{
int nConnections = m_vec.GetSize();
int nConnectionIndex = 0;
HRESULT hrTemp = S_OK;
// Go through each and every IUnknown pointers in m_vec and
// store each pointer in m_COMThread.
for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
{
Lock();
CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
Unlock();
IUnknown* pIUnknownTemp = reinterpret_cast<IUnknown*>(sp.p);
if (pIUnknownTemp)
{
// Also no need to call pIUnknownTemp->Release(). pIUnknownTemp is a temporary pointer
// to the IUnknown pointer in sp. And sp will automatically call Release() on its
// internal IUnknown pointer.
m_COMThread.AddUnknownPointer(pIUnknownTemp);
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
Lim Bio Liong is a Specialist at a leading Software House in Singapore.
Bio has been in software development for over 10 years. He specialises in C/C++ programming and Windows software development.
Bio has also done device-driver development and enjoys low-level programming. Bio has recently picked up C# programming and has been researching in this area.