Click here to Skip to main content
15,893,668 members
Articles / Desktop Programming / WTL

Use your own ATL-Objects in Dev-Studio Macros

Rate me:
Please Sign up or sign in to vote.
1.00/5 (1 vote)
17 Feb 20023 min read 48.5K   243   9  
Shows how to develop ATL-Objects to extend VB-Script. Uses ISharedPropertyGroupManager to keep data in memory. Supervises MSDEV-shutdown.
#ifndef _TC_ATL_HELPER
#define _TC_ATL_HELPER

// RELEASE_TRACE 
#ifndef RELEASE_TRACE
	#ifdef _USE_RELEASE_TRACE
		#define RELEASE_TRACE AtlTrace
	#else
		#define RELEASE_TRACE 	1 ? (void)0 : AtlTrace
	#endif
#endif



// Template Class to derive from, for deleting modeless dialogs 
// Behaves like delete this in MFC-Dialogs in PostNcDestroy 
template <class T>
class CSelfDeleteAtlDlg
{
public:
	CSelfDeleteAtlDlg() {m_szDbgClassName = _T("Unknown");}
	// Call this method to destroy a modeless ATL-Dialog
	BOOL DestroyWindowAndDeleteThis()
	{
		static_cast<T*>(this)->m_thunk.Init( DestroyWindowProc, static_cast<T*>(this));
		if (0 == WM_ATLDESTROY_MODELESS) 
		{
			WM_ATLDESTROY_MODELESS = RegisterWindowMessage( _T("DestroyModelessAtlWindow"));
		}
		static_cast<T*>(this)->PostMessage( WM_ATLDESTROY_MODELESS);
		return TRUE;
	}
private:
	static LRESULT CALLBACK DestroyWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
	{
		LRESULT lResult = 0L;
		try
		{
			T* pThis = reinterpret_cast<T*>( hWnd);
			if (WM_ATLDESTROY_MODELESS == uMsg) 
			{
				::DestroyWindow( pThis->m_hWnd);
				RELEASE_TRACE("Deleting Pointer(%s)  %08x", pThis->m_szDbgClassName, pThis);
				delete pThis;
			}
			else 
			{
				lResult = pThis->DialogProc( hWnd, uMsg, wParam, lParam);
			}
		}
		catch(...) 
		{
			ATLASSERT(false);	// Hopefully never happenes
		}
		return lResult;
	}
protected:
	LPCTSTR m_szDbgClassName;
};
__declspec(selectany) UINT  WM_ATLDESTROY_MODELESS = 0;

// This class installs a message hook to filter the WM_QUIT
// message. A derived class will be informed to do some clean up stuff
class CProcessWatcherThread
{
public:
	CProcessWatcherThread()
	{
		m_hThread						= NULL;
		m_WaitHandles.hWatchProcess		= NULL;
		m_WaitHandles.hEventStopWatch	= NULL;
		m_pProcessWatcherThread			= this;
	}
	~CProcessWatcherThread()
	{
		StopWatch();
		m_pProcessWatcherThread = NULL;
	}
	// This method is called if the process is shutting down
	virtual void OnProcessShutdown() = 0;
	void StartWatch()
	{
		if (m_hThread)	// allready running
			return;

		// Hook into applications main message loop
		m_hOriginalHook = SetWindowsHookEx(WH_GETMESSAGE, ProcessGetMessageHook, 0, GetCurrentThreadId());
		
		// Create two events, one that indicates normal exit (hEventStopWatch)
		// and another which indicated Porcess is goiing down (hWatchProcess)
		m_WaitHandles.hEventStopWatch	= ::CreateEvent(NULL, FALSE, FALSE, NULL);
		m_WaitHandles.hWatchProcess		= ::CreateEvent(NULL, FALSE, FALSE, NULL);

		// Create a thread which is supervising the events
		m_hThread = ::CreateThread(NULL, NULL, StartThread, this, 0, &m_dwThreadID);
	}
	void StopWatch()
	{
		StopWatch(m_WaitHandles.hEventStopWatch);	// Signal normal exit and unhook
	}
private:
	void StopWatch(HANDLE hStop, bool bUnhook = true)
	{
		if (!m_WaitHandles.hEventStopWatch) return;
		::SetEvent(hStop);
		::WaitForSingleObject(m_hThread, 2000);

		CloseHandle(m_WaitHandles.hEventStopWatch);
		CloseHandle(m_hThread);
		CloseHandle(m_WaitHandles.hWatchProcess);
		m_WaitHandles.hEventStopWatch	= NULL;
		m_WaitHandles.hWatchProcess		= NULL;
		m_hThread						= NULL;

		if (bUnhook)
		{
			UnhookWindowsHookEx(m_hOriginalHook);
			m_hOriginalHook = NULL;
		}
	}
	static DWORD WINAPI StartThread(LPVOID lpParameter)
	{
		CProcessWatcherThread* m_pProcessWatcherThread = (CProcessWatcherThread*) lpParameter;
		m_pProcessWatcherThread->Watch();
		return 0;
	};
	void Watch()
	{
		DWORD  dwWait = ::WaitForMultipleObjects( sizeof(m_WaitHandles) / sizeof(HANDLE), &m_WaitHandles.hWatchProcess , FALSE, INFINITE);
		if (dwWait == WAIT_OBJECT_0) // Process is terminated !!
		{		
				RELEASE_TRACE("CProcessWatcherThread: Process terminated.. calling OnProcessShutdown");
				OnProcessShutdown();
		}
		else if (dwWait == WAIT_OBJECT_0 + 1) // thread is terminated !!
		{		
				RELEASE_TRACE("CProcessWatcherThread:  Normal exit");
		}
		else 
		{		
				RELEASE_TRACE("CProcessWatcherThread: oops");
		}
	}
	
	static LRESULT CALLBACK ProcessGetMessageHook(int code, WPARAM wParam, LPARAM lParam)
		{
			MSG* pMsg = (MSG*) (lParam);
			HHOOK hookCall  = m_hOriginalHook;
			if (pMsg->message == WM_QUIT)
			{
				m_pProcessWatcherThread->StopWatch(m_pProcessWatcherThread->m_WaitHandles.hWatchProcess, false);

				LRESULT lres =  CallNextHookEx(hookCall, code, wParam, lParam);
				UnhookWindowsHookEx(m_hOriginalHook);
				m_hOriginalHook = NULL;
				return lres;
			}
			return CallNextHookEx(hookCall, code, wParam, lParam);
		}	

	DWORD							m_dwThreadID;
	HANDLE							m_hThread;
	static	HHOOK					m_hOriginalHook;
	static	CProcessWatcherThread*	m_pProcessWatcherThread;

#pragma pack( push, 1 )
	struct
	{
		HANDLE	hWatchProcess;
		HANDLE	hEventStopWatch;
	} m_WaitHandles;
#pragma pack( pop )
};

__declspec(selectany) HHOOK	CProcessWatcherThread::m_hOriginalHook = NULL;
__declspec(selectany) CProcessWatcherThread* CProcessWatcherThread::m_pProcessWatcherThread = NULL;

#endif _TC_ATL_HELPER


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
Germany Germany
I'm a (paid) software-developer since about 1995. All started in 1983 with hacking assembly code on a commodore 64. I'm using the one and only Language "C++" since 1996. I know others like VB Java TCL/TK (Sometime I was forced to use them) but they can't be compared to the power and mystic of C++.

Comments and Discussions