Re: HOWTO set up minimal sink object in console COM client?
From: Mateusz Qoskot?= (mateusz_at_loskot.net)
Date: 03/10/05
- Next message: Mateusz Qoskot?=: "Re: Is this consider as the reentrancy problem?"
- Previous message: Semut: "Re: LPDISPATCH or IDispatch*"
- In reply to: Alexander Nickolov: "Re: HOWTO set up minimal sink object in console COM client?"
- Next in thread: Alexander Nickolov: "Re: HOWTO set up minimal sink object in console COM client?"
- Reply: Alexander Nickolov: "Re: HOWTO set up minimal sink object in console COM client?"
- Messages sorted by: [ date ] [ thread ]
Date: Wed, 09 Mar 2005 19:44:40 -0800
Hi,
Thank you Alexander for your help.
Below I'm trying to explaining what I've done already.
Please, let me to add a little explanation related to my objectives.
Here is my MyObject declaration:
class ATL_NO_VTABLE CMyObject :
public CWindowImpl<CMyObject>,
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CMyObject, &CLSID_MyObject>,
public ISupportErrorInfo,
public IConnectionPointContainerImpl<CMyObject>,
public CProxy_IMyObjectEvents<CMyObject>,
public IDispatchImpl<IMyObject, &IID_IMyObject, &LIBID_MYOBJECTLib,
/*wMajor =*/ 1, /*wMinor =*/ 0>
{
// ....
STDMETHOD(StartLongTask)(void); // creates worker thread
};
I create worker thread in StartLongTask call (I use _beginthreadex)
so I derive my CMyObject from CWindowImpl because I want to be able to
PostMessage from Thread Procedure to the COM Object in order to fire
events to client.
This is a simple architecture based on the Microsoft solution presented
in this article:
http://support.microsoft.com/kb/q196026/
So, my console based COM object client should be able to response to
events fired
by the COM object above, the same way as VB client does.
In article <ezqqRd0IFHA.1996@TK2MSFTNGP12.phx.gbl> Alexander Nickolov
wrote:
> You start a regular console project, then add minimal ATL
> support - atlbase.h and atlcom.h, with the _Module in between
> in ATL3 (ATL7 doesn't need it anymore).
Yes, I have it declared in stdafx.h of my client project:
#include <atlbase.h>
extern CComModule _Module; // declared in main.cpp of the client
#include <atlcom.h>
Then in main.cpp file of my client (there is also _tmain app entry
point)
I have _Module and object map declared:
CComModule _Module;
BEGIN_OBJECT_MAP(ObjectMap) // intencionally left empty
END_OBJECT_MAP()
> Then depending
> on the type of event interface you are suing you either need
> IDispEvent[Simpel]Impl for a dispinterface, or a simle ATL
> object for a COM interface. For the latter you need to derive
> from CComObjectRootEx<CComXxxThreadModel> and
> the event interface you are implementing, then add an interface
> map with that interface, and finally implement the interface
> itself.
So, does it mean sink object is always COM object?
I think so but I'd like to be sure :-)
OK, here is my versiom - dispinterface based (MyObject is main COM
object).
My MYOBJECT.idl contains source interface declared as follows:
dispinterface _IMyObjectEvents
{
// metthods
[id(1)] HRESULT OnTaskStarted([in] long Counter);
}
Then my sink class is declared this way:
class CEventHandler :
public IDispEventImpl<0, CEventHandler, &DIID__IMyObjectEvents,
&LIBID_MYOBJECTLib, 1, 0>
{
void __stdcall OnTaskStarted(long counter)
{ g_bFinish = true; // event handled - set global flag }
BEGIN_SINK_MAP(CEventHandler)
SINK_ENTRY_EX(0, DIID__IMyObjectEvents, 1, OnTaskStarted)
END_SINK_MAP()
};
> You use AtlAdvise/AtlUnadvise to attach/detach your
> sink object (for the dispinterface sink you use DispEventAdvise
> instead).
Yes, I use DispEventAdvise as my sink is derived
from IDispEventImpl and dispinterface.
> You use CComObject<your_sink>::CreateInstance
> to create an instance of your sink object.
> Beware your object
> has refernce count of zeor when created so you should imediately
> AddRef and Release after finished advising (to take care of
> proper disposal in case of failure).
> Use GetUnknown() to get
> your sink object's IUnknown pointer (to pass to AtlAdvise).
>
Hm, in one of examples on m.p.vc.atl group I found object creation
using "new" operator withouth any refs counting (add/relese) like this:
CEventHandler * pSink = new CEventHandler();
pSink->DispEventAdvise(spUnk);
But it seems very suspicious to me.
So, now I know I have to create sink object as common COM object
in COM way. Right?
OK, thanks for giving me such great light to my COM knowledge :-)
Below I put my _tmain() function of my console-basd COM client.
I have one more problem with message map
Could you be so kind and review my code below and explain
things marked in comments?
// COM _Module declared above
// COM object map declared above
//
int _tmain(int argc, _TCHAR* argv[])
{
// globals
g_hInstance = NULL;
g_bFinish = FALSE;
std::cout << "INITIALIZE" << std::endl;
// ##### Here I use COINIT_MULTITHREADED, is that correct for my COM
// object above?
// I think I could use apartment too, right?
HRESULT hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
_ASSERTE(SUCCEEDED(hr));
{ // start of COM object life block
std::cout << " INIT" << std::endl;
g_hInstance = ::GetModuleHandle(NULL);
_Module.Init(ObjectMap, g_hInstance, &GUID_NULL);
IMyObjectPtr spMyObj;
spMyObj.CreateInstance(CLSID_MyObject);
IUnknownPtr spUnk = spMyObj;
//CEventHandler * pSink = new CEventHandler(); //
CComObject<CEventHandler> * pSink;
hr = CComObject<CEventHandler>::CreateInstance(&pSink)
_ASSERTE(SUCCEEDED(hr));
pSink->AddRef();
pSink->DispEventAdvise(spUnk);
std::cout << " TASK" << std::endl;
spMyObj->StartLongTask(); // creates worker thread
// ##### Here is my problem, when I uncomment
// all those *Message calls, this loop hangs in
// GetMessage. I'm really confused if I should use real message
// loop here, should I? This is console app, so it has no window :-)
// but COM object has its own message loop implemented by CWindowImpl
// so I think here should be only non-message-loop waiting for
// flag set by event handler (waiting for event).
// Is it good solution?
MSG msg;
while (!g_bFinish) // && GetMessage(&msg, NULL, 0, 0))
{
//TranslateMessage(&msg);
if (g_bFinish) // event handler sets this flag
std::cout << " FINISH" << std::endl;
//DispatchMessage(&msg);
}
pSink->DispEventUnadvise(spUnk);
pSink->Release();
std::cout << " END" << std::endl;
_Module.Term();
std::cout << " TERM" << std::endl;
} // end of COM object life block
::CoUninitialize();
std::cout << "UNINITIALIZE" << std::endl;
return 0;
} // end of _tmain()
Uff, that was my another long post on this group>
Thank you very much for your help.
Greets
-- Mateusz Łoskot e-mail: mateusz at loskot dot net www: http://loskot.net/about/contact/
- Next message: Mateusz Qoskot?=: "Re: Is this consider as the reentrancy problem?"
- Previous message: Semut: "Re: LPDISPATCH or IDispatch*"
- In reply to: Alexander Nickolov: "Re: HOWTO set up minimal sink object in console COM client?"
- Next in thread: Alexander Nickolov: "Re: HOWTO set up minimal sink object in console COM client?"
- Reply: Alexander Nickolov: "Re: HOWTO set up minimal sink object in console COM client?"
- Messages sorted by: [ date ] [ thread ]