***REMARK - VERSION 1 ***
in this version i created the thread, and only then called CoMarshalInterThreadInterfaceInStream(). then,
in the handler of the thread, i need to call CoGetInterfaceAndReleaseStream(). but the handler needs to
know when the stream is ready; so i need to create even with WaitForSingleObject()...
// MessageFilterClientConsole.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <objbase.h>
#import "../MessageFilterServer/MessageFilterServer.tlb" no_auto_exclude /*warning C4192, IMessageFilter*/
const int c_nNumCalls = 5;
const int c_nNumThreads = 2;
static IStream* g_pStreamPtr[c_nNumThreads]; //where to write the marshaled ptr
static HANDLE g_hEventWritten[c_nNumThreads]; //thread synchronization for read/write
static HANDLE g_hEventEndProg; //thread synchronization for ending the program
#define WM_MY_QUIT (WM_USER+1)
void Init(); //init the events
struct SMainThreadData
{
DWORD m_dwMainThreadId;
HANDLE m_hEventWritten;
int m_nThreadIndex;
};
DWORD WINAPI ThreadFunc( LPVOID lpParam )
{
CoInitialize(NULL);
SMainThreadData* pMainThreadData = (SMainThreadData*)lpParam;
HRESULT hr;
//wait for the main thread to signal that ptr is available:
DWORD dwWaitStatus = WaitForSingleObject(pMainThreadData->m_hEventWritten, 10000);
int i;
switch(dwWaitStatus)
{
case WAIT_ABANDONED:
i = 3;
break;
case WAIT_OBJECT_0:
i = 54;
break;
case WAIT_TIMEOUT:
MessageBox( NULL, "ThreadFunc(): WaitForSingleObject Timeout!!!", "ThreadFunc", MB_OK );
break;
case WAIT_FAILED:
dwWaitStatus = GetLastError();
break;
default:
i = 6;
}
IStream*& pStream = g_pStreamPtr[pMainThreadData->m_nThreadIndex];
//read marshaled object reference from global variable:
MessageFilterServerLib::IServerPtr serverPtr;
MessageFilterServerLib::IServer* pServerInfc = NULL;
hr = CoGetInterfaceAndReleaseStream(
pStream,
__uuidof(MessageFilterServerLib::IServerPtr),
(void**)&pServerInfc
);
pStream = NULL;
if(FAILED(hr))
{
MessageBox( NULL, "CoGetInterfaceAndReleaseStream() failed", "ThreadFunc", MB_OK );
}
else
{
for(int i = 0; i < c_nNumCalls; ++i)
{
//if i call Foo(), in case of fail COM throws exception. so i use raw_Foo:
hr = pServerInfc->raw_Foo();
}
}
//SetEvent(g_hEventEndProg); //see remark below (WaitForSingleObject in main thread)
BOOL b = PostThreadMessage(
pMainThreadData->m_dwMainThreadId,
WM_MY_QUIT,
0,
0);
CoUninitialize();
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
CoInitialize(NULL);
Init();
/***********************/
MessageFilterServerLib::IMyMessageFilterPtr MessageFilterPtr;
HRESULT hr = MessageFilterPtr.CreateInstance(__uuidof(MessageFilterServerLib::MyMessageFilter));
if (FAILED(hr))
{
//do something
std::cout << "main(): failed to CreateInstance of MessageFilter\n";
}
hr = MessageFilterPtr->raw_registerMessageFilter();
if (FAILED(hr))
std::cout << "main(): failed to register the MessageFilter\n";
/***********************/
MessageFilterServerLib::IServerPtr serverPtr;
hr = serverPtr.CreateInstance(__uuidof(MessageFilterServerLib::Server));
if(FAILED(hr))
{
return 0;
}
DWORD dwThreadId;
char szMsg[80];
static SMainThreadData MainThreadData[c_nNumThreads];
//thread A
MainThreadData[0].m_dwMainThreadId = GetCurrentThreadId();;
MainThreadData[0].m_hEventWritten = g_hEventWritten[0];
MainThreadData[0].m_nThreadIndex = 0;
HANDLE hWorkerThreadA = CreateThread(
NULL, // default security attributes
0, // use default stack size
ThreadFunc, // thread function
(void*)&MainThreadData[0], // argument to thread function
0, // use default creation flags
&dwThreadId); // returns the thread identifier
hr = CoMarshalInterThreadInterfaceInStream(
__uuidof(MessageFilterServerLib::IServerPtr),
serverPtr.GetInterfacePtr(),
&g_pStreamPtr[0]);
if(FAILED(hr))
{
MessageBox( NULL, "CoMarshalInterThreadInterfaceInStream() failed", "main()", MB_OK );
}
SetEvent(g_hEventWritten[0]);
//thread B
MainThreadData[1].m_dwMainThreadId = GetCurrentThreadId();;
MainThreadData[1].m_hEventWritten = g_hEventWritten[1];
MainThreadData[1].m_nThreadIndex = 1;
HANDLE hWorkerThreadB = CreateThread(
NULL, // default security attributes
0, // use default stack size
ThreadFunc, // thread function
(void*)&MainThreadData[1], // argument to thread function
0, // use default creation flags
&dwThreadId); // returns the thread identifier
hr = CoMarshalInterThreadInterfaceInStream(
__uuidof(MessageFilterServerLib::IServerPtr),
serverPtr.GetInterfacePtr(),
&g_pStreamPtr[1]);
if(FAILED(hr))
{
MessageBox( NULL, "CoMarshalInterThreadInterfaceInStream() failed", "main()", MB_OK );
}
SetEvent(g_hEventWritten[1]);
//till here thread B
// i thought i can use WaitForSingleObject, with event to signal from the worker thread when
//it is over, and then the program will end. but WaitForSingleObject blocks the main thread - the STA. so
//it prevents COM to get the calls. so comment this line:
// DWORD dwWaitStatus = WaitForSingleObject(g_hEventEndProg, INFINITE);
int nThreadCounter(0);
MSG msg;
while (GetMessage(&msg, 0, 0, 0))
{
DispatchMessage(&msg);
switch(msg.message)
{
case WM_MY_QUIT:
{
if(++nThreadCounter == c_nNumThreads)
{
char c;
std::cin >> c;
return 0;
}
}
break;
}
}
return 0;
}
/*****************************************************************************/
/*****************************************************************************/
void Init()
{
for(int i = 0; i < c_nNumThreads; ++i)
{
g_hEventWritten[i] = CreateEvent(
NULL, // no security attributes
FALSE, // non manual-reset event
FALSE, // initial state is not-signaled
NULL //no name
);
}
g_hEventEndProg = CreateEvent(
NULL, // no security attributes
FALSE, // non manual-reset event
FALSE, // initial state is not-signaled
NULL //no name
);
}