Click here to Skip to main content
15,895,142 members
Articles / Desktop Programming / ATL

An ATL Component in C++ that fires COM events

Rate me:
Please Sign up or sign in to vote.
4.19/5 (12 votes)
14 Jun 20048 min read 88.4K   3K   38  
A COM component that implements interprocess communication, and illustrates firing events to a COM container such as Visual Basic
// IPC.h : Declaration of the CIPC
#pragma once
#include "resource.h"       // main symbols
#include <atlctl.h>
#include "InterProcessComms.h"
#include "_IIPCEvents_CP.h"

// My additonal defines
#define HIDDEN_WIN_NAME "NBD_IPC_COMMS_HIDDEN"
#define HIDDEN_WIN_GUID "6845D89A-A80C-4e54-9D94-AE2BBBE182E3"
#define HIDDEN_PROP_DATA_VALUE  (HANDLE) 1

// CIPC
class ATL_NO_VTABLE CIPC : 
	public CComObjectRootEx<CComSingleThreadModel>,
	public IDispatchImpl<IIPC, &IID_IIPC, &LIBID_InterProcessCommsLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
	public IPersistStreamInitImpl<CIPC>,
	public IOleControlImpl<CIPC>,
	public IOleObjectImpl<CIPC>,
	public IOleInPlaceActiveObjectImpl<CIPC>,
	public IViewObjectExImpl<CIPC>,
	public IOleInPlaceObjectWindowlessImpl<CIPC>,
	public IConnectionPointContainerImpl<CIPC>,
	public CProxy_IIPCEvents<CIPC>, 
	public CComCoClass<CIPC, &CLSID_IPC>,
	public CComControl<CIPC>
{
public:

	CIPC()
		: m_msg_hWnd(0)
		, oldWndProc(0)
	{
	}

DECLARE_OLEMISC_STATUS(OLEMISC_RECOMPOSEONRESIZE | 
	OLEMISC_INVISIBLEATRUNTIME |
	OLEMISC_CANTLINKINSIDE | 
	OLEMISC_INSIDEOUT | 
	OLEMISC_ACTIVATEWHENVISIBLE | 
	OLEMISC_SETCLIENTSITEFIRST
)

DECLARE_REGISTRY_RESOURCEID(IDR_IPC)

BEGIN_COM_MAP(CIPC)
	COM_INTERFACE_ENTRY(IIPC)
	COM_INTERFACE_ENTRY(IDispatch)
	COM_INTERFACE_ENTRY(IViewObjectEx)
	COM_INTERFACE_ENTRY(IViewObject2)
	COM_INTERFACE_ENTRY(IViewObject)
	COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless)
	COM_INTERFACE_ENTRY(IOleInPlaceObject)
	COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless)
	COM_INTERFACE_ENTRY(IOleInPlaceActiveObject)
	COM_INTERFACE_ENTRY(IOleControl)
	COM_INTERFACE_ENTRY(IOleObject)
	COM_INTERFACE_ENTRY(IPersistStreamInit)
	COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit)
	COM_INTERFACE_ENTRY(IConnectionPointContainer)
END_COM_MAP()

BEGIN_PROP_MAP(CIPC)
	PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4)
	PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4)
	// Example entries
	// PROP_ENTRY("Property Description", dispid, clsid)
	// PROP_PAGE(CLSID_StockColorPage)
END_PROP_MAP()

BEGIN_CONNECTION_POINT_MAP(CIPC)
	CONNECTION_POINT_ENTRY(__uuidof(_IIPCEvents))
END_CONNECTION_POINT_MAP()

BEGIN_MSG_MAP(CIPC)
	CHAIN_MSG_MAP(CComControl<CIPC>)
	DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()
// Handler prototypes:
//  LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
//  LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
//  LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);

// IViewObjectEx
	DECLARE_VIEW_STATUS(VIEWSTATUS_SOLIDBKGND | VIEWSTATUS_OPAQUE)

// IIPC
public:
		HRESULT OnDraw(ATL_DRAWINFO& di)
		{
		RECT& rc = *(RECT*)di.prcBounds;
		// Set Clip region to the rectangle specified by di.prcBounds
		HRGN hRgnOld = NULL;
		if (GetClipRgn(di.hdcDraw, hRgnOld) != 1)
			hRgnOld = NULL;
		bool bSelectOldRgn = false;

		HRGN hRgnNew = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);

		if (hRgnNew != NULL)
		{
			bSelectOldRgn = (SelectClipRgn(di.hdcDraw, hRgnNew) != ERROR);
		}

		Rectangle(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom);
		SetTextAlign(di.hdcDraw, TA_CENTER|TA_BASELINE);
		LPCTSTR pszText = _T("ATL 7.0 : IPC");
		TextOut(di.hdcDraw, 
			(rc.left + rc.right) / 2, 
			(rc.top + rc.bottom) / 2, 
			pszText, 
			lstrlen(pszText));

		if (bSelectOldRgn)
			SelectClipRgn(di.hdcDraw, hRgnOld);

		return S_OK;
	}


	DECLARE_PROTECT_FINAL_CONSTRUCT()

	// Constructor for the IPC class object
	HRESULT FinalConstruct()
	{
		m_msg_hWnd = CIPC::InitComms();
		if (m_msg_hWnd == 0 ) {
			// there is an error
			return E_FAIL;
		}
		return S_OK;
	}

	// Destructor
	void FinalRelease() 
	{
		CIPC::EndComms();
	}

private:
	// This holds the hWnd of our hidden window used to pass messages
	HWND m_msg_hWnd;
	// Create an array of HWNDs for storing the hidden window handles
	CSimpleArray<HWND> m_hWndArray;
	// Storage for the old WndProc address
	long oldWndProc;

public:
	// Property function to return the handle of the hidden windo
	STDMETHOD(get_msghWnd)(LONG* pVal);
	// Method used to send data
	STDMETHOD(SendData)(LONG lData, BSTR sData, LONG hWnd);
	// Window proc function
	LRESULT MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

private:
	// Private function to init the IPC
	HWND InitComms(void);
	// // Private function to end the IPC
	int EndComms(void);
	// Start the enumeration of all top level windows, to find all our hidden msg windows
	int EnumerateWindows(void);
	// The call back function for Enumerate Windows
	BOOL CIPC::EnumWindowsProc(HWND hWnd, DWORD lParam);

	// The global static member function that can be used as a function for
	static LRESULT CALLBACK GlobalWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
};

OBJECT_ENTRY_AUTO(__uuidof(IPC), CIPC)

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
Web Developer
United Kingdom United Kingdom
I am a Surgeon by trade, but have been programming since I could reach the keyboard! I run a surgical website and am MD of a company that writes Surgical Software.

Comments and Discussions