Click here to Skip to main content
15,885,546 members
Articles / Desktop Programming / ATL

How to Use IMessageFilter: the complete edition

Rate me:
Please Sign up or sign in to vote.
4.00/5 (8 votes)
19 Feb 20066 min read 51.1K   536   23  
This article shows you exactly how to create a COM object that uses IMessageFilter - both in client and server sides.
***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
		);
}

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Israel Israel
working for Intel

My Linkedin Profile

Visit my photography gallery

Comments and Discussions