/* =============================================================================
* 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;
}
}