|
-
July 15th, 2008, 05:08 AM
#1
[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.
-
July 15th, 2008, 10:39 AM
#2
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.
-
July 15th, 2008, 11:08 AM
#3
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
-
July 15th, 2008, 10:57 PM
#4
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);
}
};
-
July 16th, 2008, 04:33 AM
#5
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.
-
July 16th, 2008, 06:32 AM
#6
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
-
July 16th, 2008, 07:20 AM
#7
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.
-
July 16th, 2008, 07:33 AM
#8
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
-
July 16th, 2008, 07:43 AM
#9
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.
-
July 16th, 2008, 12:37 PM
#10
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".
-
July 17th, 2008, 02:47 AM
#11
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
-
July 17th, 2008, 04:28 AM
#12
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.
-
July 17th, 2008, 05:29 AM
#13
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
-
July 18th, 2008, 02:27 AM
#14
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 )
-
July 18th, 2008, 05:23 AM
#15
Re: worker thread to fire events in COM?
 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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|