CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 15 of 15
  1. #1
    Join Date
    Nov 2000
    Posts
    154

    [RESOLVED] worker thread to fire events in COM?

    Hi..

    There's a C++ COM-server (runs as a service), & a C# COM-client.
    In COM server, an event is implemented as shown below..
    Code:
     
    //C++ header
    
    __interface _ITestEvents 
    {
    	[id(1), helpstring("method MyEvent"), source] HRESULT MyEvent([in] SHORT size,   [in, satype(byte)] SAFEARRAY * byData);
    
    }
    The event is fired when needed..
    Code:
     
    //C++ source
    
    {
    	//...
    	Long lVal = MyEvent(size, byData);
    }
    The C# client receives the event successfully ( lVal is zero ).

    Code:
    //C#
    
    m_ComObj.MyEvent += new TestCom._ITestEvents_MyEventEventHandler(OnMyEvent);
    ///......
    void OnMyEvent(short size, System.Array data)
    {
          txtBox1.Text = "received event";
    }
    As a multi-threaded requirement is needed I’ve created a thread using "CreateThread". In the thread function if I fire the same event, the C# client doesn’t receive it ( lVal is always non-zero ).

    Why I can’t use a worker thread to fire an event?
    Last edited by asinro; July 15th, 2008 at 05:42 AM.

  2. #2
    Join Date
    Feb 2005
    Posts
    2,160

    Re: worker thread to fire events in COM?

    We'd probably need to see the thread code to see what's wrong. Off the top of my head, make sure you are calling CoInitialize[Ex] in the new thread. You must call this in every thread that uses OLE.

  3. #3
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,633

    Re: worker thread to fire events in COM?

    As a multi-threaded requirement is needed I’ve created a thread using "CreateThread". In the thread function if I fire the same event, the C# client doesn’t receive it ( lVal is always non-zero ).

    Why I can’t use a worker thread to fire an event?
    My impression is your server is apartment-threaded one. If yes, you have to marshall the event interface to a worker thread to be able fire events from there.
    Best regards,
    Igor

  4. #4
    Join Date
    Nov 2000
    Posts
    154

    Re: worker thread to fire events in COM?

    Thanks guys.
    Igor, can you pl. explain..
    hoxsiew, here is some code snippets.

    This is from the COM interface:
    Code:
    //	C++ header - COM
    __interface ITest : IDispatch
    {
           //……some functions
    };
    __interface _ITestEvents 
    {
    	[id(1), helpstring("method MyEvent"), source] HRESULT MyEvent([in] SHORT size,   [in, satype(byte)] SAFEARRAY * byData);
    
    };
    
    
    [
    	coclass,
    	default(ITest, _ ITestEvents),
    	threading(free),
    	event_source(com),
    	vi_progid("Test.Test"),
    	progid("Test.Test.1"),
    	version(1.0),
    	uuid("9F8D4F16-0F61-4A38-98B3-1F6F80F11C87"),
    	helpstring("CTest Class")
    ]

    Code:
    DWORD WINAPI MyThreadProc(LPVOID lpParam) 
    {
    	CSample *pSample = (CSample*)lpParam;
    	if(NULL != pSample)
    	{
    		pSample ->MyThread();
    	}
    	return 0; 
    }
    
    void CSample::StartThread()
    {
    	InitializeCriticalSection(&m_crSec);
    	m_hThreadExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    	DWORD dwThreadId = 0;
    m_hThread = CreateThread(NULL, 0, MyThreadProc, (LPVOID)this,     0, &dwThreadId);		 
    }
    
    void CSample::MyThread()
    {
    	while(WAIT_OBJECT_0 != WaitForSingleObject(m_hThreadExitEvent, 0))
    	{
    		EnterCriticalSection(&m_crSec);
    		// m_pTest – valid pointer of COM class CTest
    		Long lVal = m_pTest->MyEvent(size, byData);
    		LeaveCriticalSection(&m_crSec);
    		Sleep(500);
    	}
    }
    This is the Service:
    Code:
     
    [ module(SERVICE, uuid = "{DB07B9FC-18B0-4B55-9A44-31D2C2F87875}", 
    		 name = "Test", 
    		 helpstring = " Test 1.0 Type Library", 
    		 resource_name="IDS_SERVICENAME") ]
    
    
    class CTestModule
    {
    public:
    	HRESULT InitializeSecurity() throw()
    	{
    		return S_OK;
    	}
    
    	CTestModule ()
    	{
    		m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    	}
    	
    	HRESULT Run(int nShowCmd = SW_HIDE) throw()
    	{
    		HRESULT hr;
    		hr = CoInitialize(NULL);
    		 
    	   CSecurityDescriptor sd;
    	   sd.InitializeFromThreadToken();
    	   hr = CoInitializeSecurity(sd, -1, NULL, NULL,
    		  RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
    	   
    		hr = this->RegisterClassObjects(CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, REGCLS_MULTIPLEUSE);
    	
    		LogEvent(_T("Service started"));
    		if (m_bService)
    			SetServiceStatus(SERVICE_RUNNING);
    
    		this->RevokeClassObjects();
    
    		// InitMywork(); // start CSample work
    
    		return  __super::Run(nShowCmd);
    	}
    
    	};

  5. #5
    Join Date
    Jul 2001
    Location
    Netherlands
    Posts
    751

    Re: worker thread to fire events in COM?

    I think that in your thread function when the event is to be fired, you need to from the thread function notify the main thread to fire the event.
    So pass the *this* pointer along to the thread function and when you need to fire the event tell the *this* pointer to fire the event.

  6. #6
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,633

    Re: worker thread to fire events in COM?

    Igor, can you pl. explain..
    Better read this below. In case you find you need some further discussion, please let me know.

    The article section: Don't Pass Raw Interface Pointers Between Threads
    Last edited by Igor Vartanov; July 16th, 2008 at 06:34 AM.
    Best regards,
    Igor

  7. #7
    Join Date
    Jul 2001
    Location
    Netherlands
    Posts
    751

    Re: worker thread to fire events in COM?

    As a workaround to passing the interface pointer, which requires marshalling, for this kind of situation I usually let the Com class derive from a regular C++ class with a virtual function that is implemented in the com class. The base C++ class starts the thread passing its *this* pointer, and when the event is to be called from the thread, the virtual function is triggered in the com class in the original thread.
    You are also likely to need critical sections when doing this.

  8. #8
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,633

    Re: worker thread to fire events in COM?

    The base C++ class starts the thread passing its *this* pointer, and when the event is to be called from the thread, the virtual function is triggered in the com class in the original thread.
    Sorry, but I cannot figure out how this may work. C++ knows nothing about threads.
    Best regards,
    Igor

  9. #9
    Join Date
    Jul 2001
    Location
    Netherlands
    Posts
    751

    Re: worker thread to fire events in COM?

    C++ knows nothing about threads
    Huh? I believe you didn't express yourself clearly, which happens to everyone.
    My point is, the base class can pass the raw *this* pointer along(as it isn't a com class). With this *this* pointer the original thread can be accessed without marshalling .
    Last edited by fransn; July 16th, 2008 at 07:47 AM.

  10. #10
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: worker thread to fire events in COM?

    Igor is right on with regard to marshalling between threads.

    For an article that wraps this up in a nice class, check out http://www.codeproject.com/KB/atl/git.aspx

    For additional info, search google for "Global interface table COM threads".

  11. #11
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,633

    Re: worker thread to fire events in COM?

    Huh? I believe you didn't express yourself clearly, which happens to everyone.
    Okay, let me elaborate my point.

    Let's put COM class aside for a while. You say:

    The base class Base provides a virtual function Base::callbackToOriginalThread.
    Thread A creates an object of a class Desc wich is a descendant of the Base.
    The this of the object is passed to thread B.
    Your essential point is that been calling this->callbackToOriginalThread in thread B you expect that virtual function will be executed in context of thread A ("the virtual function is triggered in the com class in the original thread").

    And exactly about the last statement my comment was: virtual function is a feature of C++, and C++ knows nothing about threads, so any (virtual, whatever) function will be executed in a context of the thread that invokes the call. As the consequence of this, there will be no thread context switching you expect.

    I hope I was clear enough this time.

    In case I was taking your words wrong or something, please illustrate your point with some sample code (preferrably compilable and runnable).
    Last edited by Igor Vartanov; July 17th, 2008 at 02:53 AM.
    Best regards,
    Igor

  12. #12
    Join Date
    Jul 2001
    Location
    Netherlands
    Posts
    751

    Re: worker thread to fire events in COM?

    I looked at some code I wrote about a year ago where in a COM object a thread was started and this thread needed to notify the original thread of incoming messages.
    I see now that it didn't use the *this* pointer to relay the message but that the base class derived from CAxDialogImpl<baseclass> and passed the hwnd to the started thread. The thread used SendMessage to this hwnd to communicate back to the original thread.
    So indeed the *this* pointer approach didn't work.
    This code has been used continuously by dozens of people so no problem with it.

  13. #13
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,633

    Re: worker thread to fire events in COM?

    The thread used SendMessage to this hwnd to communicate back to the original thread.
    Now it is indeed absolutely different thing, as SendMessage switches the thread contexts.

    Unfortunately the possible problem is that the solution relies on a presence of a window (that is not quite natural for service solutions). And interface marshaling never does.
    Best regards,
    Igor

  14. #14
    Join Date
    Nov 2000
    Posts
    154

    Re: worker thread to fire events in COM?

    Thanks guys again.
    Igor, your link is really helpfull. http://msdn.microsoft.com/en-us/magazine/cc302324.aspx
    hoxsiew, I didn't use CoInitializeEx in thread start. Now it's working fine with CoInitializeEx.
    (How do I rate you people. Those very early days I did rate people. Now I don't know how to do it )

  15. #15
    VictorN's Avatar
    VictorN is offline Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Hanover Germany
    Posts
    20,430

    Re: worker thread to fire events in COM?

    Quote Originally Posted by asinro
    (How do I rate you people. Those very early days I did rate people. Now I don't know how to do it )
    Just click on the Rate this post" link on the upper right corner on the post window, then add your comment...
    Victor Nijegorodov

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured