Click here to Skip to main content
15,892,809 members
Articles / Mobile Apps

The StateWizard VC++ Add-in and Engine with Source Code

Rate me:
Please Sign up or sign in to vote.
4.73/5 (24 votes)
26 Mar 2009CPOL12 min read 190.7K   2.8K   132  
A cross-platform state-oriented application framework and a ClassWizard-like round-trip UML dynamic modeling/development tool that runs in popular IDEs. Aims at providing concurrent, distributed, and real-time application development tools for Win32/Linux
/* =============================================================================
 * This notice must be untouched at all times.
 *
 * Copyright  IntelliWizard Inc. 
 * All rights reserved.
 * LICENSE: LGPL
 * Web: http://www.intelliwizard.com
 * eMail: info@intelliwizard.com
 * We provide technical support for non-commercial or commercial UML StateWizard users.
 * -----------------------------------------------------------------------------
 */
// EvcStateTrack.cpp
////////////////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "rapi.h"
#include "sme_debug.h"

/*******************************************************************************************
* DESCRIPTION: 

This state machine engine DLL will be called by 2 modules: EVC add-in and application.

EVC add-in create a window to receive state track information from application.
And then write data to add-in using ActiveSyn in stream mode.

Application posts state track information to that window.	

*******************************************************************************************/

///// Shared data section among DLL callers.
///// Link: /SECTION:Shared,RWS 
///// or #pragma comment(linker,"/SECTION:.Shared,RWS") 
#pragma data_seg("Shared")
volatile HWND g_hwndStateTrack = NULL;
HINSTANCE g_hInstance = NULL;
#pragma data_seg()

#pragma comment(linker,"/SECTION:.Shared,RWS") 

#define APP_NAME_SIZE  64
struct EVC_STATE_TRACK_T
{
	DWORD nState;
	char sAppName[APP_NAME_SIZE+1];
};

IRAPIStream* g_pRApiStream = NULL;

const TCHAR	STATE_TRACK_WND_CLASS_NAME[] = _T("StateTrackWnd3"); 

#define COPYDATA_WM_ID_STATE_TRACK (WM_APP+1) 

#include "stdio.h"

FILE *g_pFile=NULL;

void Trace(const char *sFmt, ...)
{
	g_pFile = fopen("\\StateTrack\\statetrackdebug.txt", "at");

	int nSize = 0;
	char buff[512];
	va_list args;
	va_start(args, sFmt);

	_vsnprintf( buff, sizeof(buff), sFmt, args);

	fputs(buff, g_pFile);
	fflush(g_pFile);
	fclose(g_pFile);
}

//#define TRACE Trace  // For debug
#define TRACE 1 ? (void)0 : Trace // For release edition

/*******************************************************************************************
* DESCRIPTION: Create a window to receive the state track information. 
* INPUT:  
*  None. 
* OUTPUT: 
* NOTE: 
	To end the running process.
	if (m_hwndMainWnd)
		SendMessage(m_hwndMainWnd, WM_DESTROY, 0,0);

	// Wait until task bar icon window thread exits.
	WaitForSingleObject(m_hThread, INFINITE);

*******************************************************************************************/
// The window procedure.
LRESULT CALLBACK EST_StateTrackWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	BOOL bCallDefWndProc = FALSE;
	long lRet = 0;

	TRACE("Receive message.\n");

	switch(message) 
	{
	case WM_DESTROY: // terminate the program 
		{
		  TRACE("Receive WM_DESTROY\n");

		  lRet = 0;
		  bCallDefWndProc = FALSE;
		  PostQuitMessage(0);
		  break;
		}
	case WM_COPYDATA:
		{
		if (COPYDATA_WM_ID_STATE_TRACK == COPYDATA_WM_ID_STATE_TRACK)
		{
			//Write the structure into the stream
			COPYDATASTRUCT *pds = reinterpret_cast< COPYDATASTRUCT * >( lParam );
			struct EVC_STATE_TRACK_T *pStateTrack = reinterpret_cast< struct EVC_STATE_TRACK_T * >( pds->lpData );

			TRACE("Receive WM_COPYDATA: app=%s state=%d\n", pStateTrack->sAppName, pStateTrack->nState );

			if (g_pRApiStream)
			{
				DWORD cbWritten=0;
				HRESULT hr = g_pRApiStream->Write(pStateTrack, sizeof(struct EVC_STATE_TRACK_T), &cbWritten);
				
				TRACE("Write to stream g_pRApiStream = %d cbWritten = %d \n", g_pRApiStream, cbWritten);
				if(FAILED(hr))
					return FALSE;
			}
		}
		break;
		}
	};
	return TRUE;
};

/*******************************************************************************************
* DESCRIPTION: Create a window to receive the state track information. 
	This function will be called by EVC addin.
* INPUT:  
*  None. 
* OUTPUT: 
* NOTE: 
	To end the running process.
	if (m_hwndMainWnd)
		SendMessage(m_hwndMainWnd, WM_DESTROY, 0,0);

	// Wait until task bar icon window thread exits.
	WaitForSingleObject(m_hThread, INFINITE);

*******************************************************************************************/
BOOL EST_CreateStateTrackWnd(HINSTANCE hInstance)
{
	// Register the main window class. 
	WNDCLASS wc; 
	DWORD dwStyle = 0; //WS_OVERLAPPEDWINDOW;  

	memset (&wc, 0, sizeof(WNDCLASS));
	wc.style			= CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc	= (WNDPROC)EST_StateTrackWndProc; 
	wc.hInstance		= hInstance;
	wc.hIcon			= NULL; //LoadIcon((HINSTANCE)NULL, IDI_WINLOGO); 
	wc.hCursor		= NULL; //LoadCursor ((HINSTANCE)NULL, IDC_ARROW);
	wc.hbrBackground = NULL; //(HBRUSH) GetStockObject(WHITE_BRUSH); 
	wc.lpszMenuName  = (LPCTSTR)NULL; // Enhancement to Window Finder - no need for menu in main window (it is invisible).
	wc.lpszClassName = STATE_TRACK_WND_CLASS_NAME; 

	TRACE(".............................\n");
	if (hInstance==NULL)
	{
		TRACE("Erro hInstance==NULL\n");
		return FALSE;
	}

	UnregisterClass
	  (
		(LPCTSTR)STATE_TRACK_WND_CLASS_NAME, // address of class name string 
		(HINSTANCE)g_hInstance // handle of application instance 
	  );

 	if (!RegisterClass(&wc)) 
	{
		TRACE("Fail to RegisterClass()\n");
		return FALSE;
	}
	
	g_hwndStateTrack = CreateWindow
		(
		STATE_TRACK_WND_CLASS_NAME,     // name of window class 
		_T(""),  // title 
		dwStyle, // window style - normal 
		CW_USEDEFAULT, // X coordinate - let Windows decide 
		CW_USEDEFAULT, // Y coordinate - let Windows decide 
		CW_USEDEFAULT, // width - let Windows decide 
		CW_USEDEFAULT, // height - let Windows decide
		NULL,          // no parent window 
		NULL,          // no override of class menu 
		hInstance,     // handle for this instance
		NULL           // no additional arguments 
		);

	if (g_hwndStateTrack==NULL)
	{
		TRACE("Fail to CreateWindow()\n");

		UnregisterClass
		  (
			(LPCTSTR)STATE_TRACK_WND_CLASS_NAME, // address of class name string 
			(HINSTANCE)g_hInstance // handle of application instance 
		  );
		return FALSE;
	}

	// Display the window. 
	if (g_hwndStateTrack)
	{
		ShowWindow(g_hwndStateTrack, SW_HIDE);  // Enhancement to WindowFinder - hide the main window.
		UpdateWindow(g_hwndStateTrack);
	}

	TRACE("Try to GetMessage()\n");

	// Create the message loop. 
	MSG msg;
	while (GetMessage(&msg, (HWND)NULL, 0, 0)) 
	{ 
		TranslateMessage(&msg); 
		DispatchMessage(&msg); 
	}

	TRACE("End of GetMessage()\n");

	// The indicator that it is time to de-register window.
	g_hwndStateTrack = NULL;
	return TRUE;

}

/*******************************************************************************************
* DESCRIPTION: This function will be called by EVC addin. 
* INPUT:  
*  None. 
* OUTPUT: 
* NOTE: 
*******************************************************************************************/
int EvcStateTrackFuncCall(DWORD dwInput, BYTE* pInput,
                   DWORD* pcbOutput, BYTE** ppOutput,
                   IRAPIStream* pStream)
{
	g_pRApiStream = pStream;

	// If this parameter is NULL, GetModuleHandle returns a handle to the file used to create the calling process.
	g_hInstance = GetModuleHandle(NULL);
	EST_CreateStateTrackWnd(g_hInstance); 

	return TRUE;
}

BOOL EvcEndStateTrackFuncCall(DWORD dwInput, BYTE* pInput,
                   DWORD* pcbOutput, BYTE** ppOutput,
                   IRAPIStream* pStream)
{

	if (g_hwndStateTrack)
	{
		SendMessage(g_hwndStateTrack, WM_DESTROY, 0,0);

		while (g_hwndStateTrack)
		{
			Sleep(1000);
			UnregisterClass
			  (
				(LPCTSTR)STATE_TRACK_WND_CLASS_NAME, // address of class name string 
				(HINSTANCE)g_hInstance // handle of application instance 
			  );
		};
	};
	return TRUE;
}

BOOL EST_DestroyStateTrackWnd()
{
	if (g_hwndStateTrack)
	{
		TRACE("SendMessage WM_DESTROY \n");
		SendMessage(g_hwndStateTrack, WM_DESTROY, 0,0);
	}
	return TRUE;
}

/*******************************************************************************************
* DESCRIPTION: Create a window to receive the state track information. 
	This function will be called by EVC state engine.
* INPUT:  
*  None. 
* OUTPUT: 
* NOTE: 
*******************************************************************************************/
BOOL EST_SendStateTrack(const char * sAppName, SME_STATE_T nNewState)
{
	struct EVC_STATE_TRACK_T StateTrack;
	memset( &StateTrack, 0, sizeof( struct EVC_STATE_TRACK_T ) );
	StateTrack.nState = nNewState;
	if (sAppName)
		strcpy(StateTrack.sAppName, sAppName);
	else
		StateTrack.sAppName[0]=0;

	COPYDATASTRUCT cds;
	memset( &cds, 0, sizeof( cds ) );
	cds.dwData = COPYDATA_WM_ID_STATE_TRACK;
	cds.cbData = sizeof(struct EVC_STATE_TRACK_T);
	cds.lpData = (PVOID)&StateTrack;
	::SendMessage( g_hwndStateTrack, WM_COPYDATA, 0, (LPARAM)&cds );

	TRACE("Send WM_COPYDATA\n");
	return TRUE;
}

typedef struct _STATE_TRACK_INFO_T
{
	char sAppName[64];
	SME_STATE_T nState;
} STATE_TRACK_INFO_T;

#define STATE_TRACK_BUF_SIZE 16

static STATE_TRACK_INFO_T g_StateTrackBuf[STATE_TRACK_BUF_SIZE];
static int g_nBufHdr=0;
static int g_nBufTail=0;

BOOL EST_StateTrack(struct SME_APP_T *pDestApp, SME_STATE_T nNewState)
{
	if (g_hwndStateTrack != NULL)
	{
		// Pop if buffer is not empty.
		while (g_nBufTail!=g_nBufHdr)
		{
			EST_SendStateTrack(g_StateTrackBuf[g_nBufTail].sAppName, g_StateTrackBuf[g_nBufTail].nState);
			g_nBufTail = (g_nBufTail+1)%STATE_TRACK_BUF_SIZE;
		}
		if (pDestApp)
			EST_SendStateTrack(pDestApp->sAppName, nNewState);
		else 
			EST_SendStateTrack(NULL, nNewState);
		return TRUE;
	} else
	{
		// Put into buffer.
		if ((pDestApp==NULL || pDestApp->sAppName==NULL) && nNewState==-1)
		{
			// End application thread. Stop state tracking.
			// Clear buffer.
			g_nBufHdr=0;
			g_nBufTail=0;
		}

		// Push
		if ((g_nBufHdr+1)%STATE_TRACK_BUF_SIZE != g_nBufTail)
		{
			if (pDestApp)
				strcpy(g_StateTrackBuf[g_nBufHdr].sAppName, pDestApp->sAppName);
			else
				g_StateTrackBuf[g_nBufHdr].sAppName[0]=0;
			g_nBufHdr=(g_nBufHdr+1)%STATE_TRACK_BUF_SIZE;
		} else
		{
			// Full, discard it.
		}
		return FALSE;
	}
}

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
Alex "Question is more important than the answer."

Comments and Discussions