// Interprocess Communication Demo
//
// This program along with the Client.dpr project, demonstrate a number
// of topics in Win32 programming. Threads, Events, Mutexes, and Shared
// memory are all used to provide communication between this monitor and
// it's clients, see IPCThrd.pas.
//
// To Run, compile this project and the Client.cpp project. Run one
// instance of the monitor and then run several instances of the client.
// You can switch between clients by clicking on the Client's window or
// by selecting it from the Client menu in the monitor.
//
// Topics Covered:
//
// Interprocess Communication
// Threads
// Events
// Mutexes
// Shared Memory
// Single instance EXE.
//
//---------------------------------------------------------------------------
#include "Monform.h"
#include "TrcView.h"
#include "About.h"
//---------------------------------------------------------------------------
#pragma resource "*.dfm"
TMonitorForm *MonitorForm;
__fastcall TMonitorForm::TMonitorForm(TComponent *Owner):TForm(Owner)
{
}
void __fastcall TMonitorForm::ClearLabels()
{
int Index;
for (Index = cfError; Index <= cfAttach; Index++)
{
TraceLabels[Index].YLabel->Caption = 0;
TraceLabels[Index].XLabel->Caption = 0;
}
}
void __fastcall TMonitorForm::OnConnect(TIPCThread* Sender, Boolean Connecting)
{
if (Connecting)
{
FStatusText = IPCMonitor->ClientName;
SignalClientStatus();
}
else
FStatusText = "No Client";
PostMessage(Handle, WM_UPDATeSTATUS, 0, 0);
}
void __fastcall TMonitorForm::OnDirectoryUpdate(TIPCThread *Sender)
{
PostMessage(Handle, WM_UPDATEMENU, 0, 0);
}
void __fastcall TMonitorForm::OnSignal(TIPCThread *Sender, const TEventData &Data)
{
FTraceMsg.X = Data.X;
FTraceMsg.Y = Data.Y;
FTraceMsg.Flag = Data.Flag;
PostMessage(Handle,
WM_SETTRACEDATA,
FTraceMsg.X,
FTraceMsg.Y);
}
void __fastcall TMonitorForm::SignalClientStatus()
{
if (PauseButton->Down == true){
TClientFlags NoFlags;
IPCMonitor->SignalClient(NoFlags);
}
else
IPCMonitor->SignalClient(FClientData.Flags);
}
void __fastcall TMonitorForm::UpdateTraceData(TWMTraceData* Msg)
{
if (FClientData.Flags.Contains(FTraceMsg.Flag))
{
TraceLabels[FTraceMsg.Flag].XLabel->Caption = String((int)Msg->X);
TraceLabels[FTraceMsg.Flag].YLabel->Caption = String((int)Msg->Y);
}
}
void __fastcall TMonitorForm::UpdateStatusBar(TMessage* Msg)
{
StatusBar->SimpleText = FStatusText;
ClearLabels();
}
void __fastcall TMonitorForm::UpdateClientMenu(TMessage* Msg)
{
int I;
int ID;
TStringList* List = new TStringList();
TMenuItem* mi;
IPCMonitor->GetClientNames(List);
while (miClients->Count > 0) {
miClients->Delete(0);
}
if (List->Count == 0)
miClients->Add(NewItem("(None)", 0, False, False, NULL, 0, ""));
else
for(I=0; I < List->Count; I++)
{
ID = (int)List->Objects[I];
mi = NewItem(List->Strings[I], 0, False, True, ClientMenuClick, 0, "");
mi->Tag = ID;
mi->RadioItem = True;
mi->GroupIndex = 1;
miClients->Add(mi);
}
delete List;
}
void __fastcall TMonitorForm::SetupLabelArray()
{
TraceLabels[cfMouseMove].XLabel = MoveX;
TraceLabels[cfMouseMove].YLabel = MoveY;
TraceLabels[cfMouseDown].XLabel = DownX;
TraceLabels[cfMouseDown].YLabel = DownY;
TraceLabels[cfResize].XLabel = SizeX;
TraceLabels[cfResize].YLabel = SizeY;
}
void __fastcall TMonitorForm::FormCreate(TObject* Sender)
{
IPCMonitor = new TIPCMonitor((int)Application->Handle, "Monitor");
IPCMonitor->OnSignal = OnSignal;
IPCMonitor->OnConnect = OnConnect;
IPCMonitor->OnDirectoryUpdate = OnDirectoryUpdate;
IPCMonitor->Activate();
OnDirectoryUpdate(NULL);
OnConnect(NULL, False);
FClientData.Flags << cfMouseMove << cfMouseDown << cfResize;
SetupLabelArray();
}
void __fastcall TMonitorForm::FormDestroy( TObject* Sender)
{
IPCMonitor->Free();
}
void __fastcall TMonitorForm::ClientMenuClick( TObject* Sender)
{
int NewID;
NewID = (int)((TMenuItem*)Sender)->Tag;
if (NewID != IPCMonitor->ClientID)
IPCMonitor->ClientID = NewID;
}
void __fastcall TMonitorForm::miClientsClick(TObject* Sender)
{
int I;
if (IPCMonitor->ClientID != 0)
for(I=0; I < miClients->Count; I++)
if (miClients->Items[I]->Tag == IPCMonitor->ClientID)
{
miClients->Items[I]->Checked = True;
break;
}
}
void __fastcall TMonitorForm::SetTraceFlags( TObject* Sender)
{
TClientFlag F;
F = (TClientFlag)((TCheckBox*)Sender)->Tag;
if (((TCheckBox*)Sender)->Checked)
FClientData.Flags << F;
else
FClientData.Flags >> F;
SignalClientStatus();
}
void __fastcall TMonitorForm::AutoClientSwitch1Click( TObject* Sender)
{
((TMenuItem*)Sender)->Checked = ! ((TMenuItem*)Sender)->Checked;
IPCMonitor->AutoSwitch = ((TMenuItem*)Sender)->Checked;
}
void __fastcall TMonitorForm::miFileExitClick( TObject* Sender)
{
Close();
}
void __fastcall TMonitorForm::ShowTraceButtonClick( TObject* Sender)
{
IPCMonitor->GetDebugInfo(TraceForm->TraceData->Items);
TraceForm->ShowModal();
}
void __fastcall TMonitorForm::PauseButtonClick( TObject* Sender)
{
SignalClientStatus();
}
void __fastcall TMonitorForm::ClearButtonClick( TObject* Sender)
{
IPCMonitor->ClearDebugInfo();
}
void __fastcall TMonitorForm::ExitButtonClick( TObject* Sender)
{
Close();
}
void __fastcall TMonitorForm::About1Click( TObject* Sender)
{
ShowAboutBox();
}
//-----------------------------------------------------------------------------
#include "IPCThrd.h"
#include
//-----------------------------------------------------------------------------
// Utility Routines
void __fastcall Error(const AnsiString Msg)
{
ShowMessage(Msg);
throw(Msg);
}
AnsiString __fastcall EventName(TEventKind Event)
{
switch (Event){
case evMonitorAttach: return "evMonitorAttach";
case evMonitorDetach: return "evMonitorDetach";
case evMonitorSignal: return "evMonitorSignal";
case evMonitorExit: return "evMonitorExit";
case evClientStart: return "evClientStart";
case evClientStop: return "evClientStop";
case evClientAttach: return "evClientAttach";
case evClientDetach: return "evClientDetach";
case evClientSwitch: return "evClientSwitch";
case evClientSignal: return "evClientSignal";
case evClientExit: return "evClientExit";
default: return "";
}
}
bool __fastcall IsMonitorRunning(THandle& Hndl)
{
TSharedMem* SharedMem;
bool Result;
SharedMem = new TSharedMem(CLIENT_DIR_NAME, 4);
Hndl = *((THandle*)(SharedMem->Buffer));
Result = (Hndl != 0);
delete SharedMem;
return Result;
}
__fastcall THandledObject::~THandledObject()
{
if (FHandle != 0)
CloseHandle(FHandle);
}
__fastcall TEvent::TEvent(const AnsiString Name, bool Manual)
{
AnsiString buf;
buf = Name + ".Data";
FHandle = CreateEvent(NULL, Manual, false, buf.c_str());
if (FHandle == 0) Abort();
}
void __fastcall TEvent::Reset()
{
ResetEvent(FHandle);
}
void __fastcall TEvent::Signal()
{
SetEvent(FHandle);
}
bool __fastcall TEvent::Wait(int TimeOut)
{
return WaitForSingleObject(FHandle, TimeOut) == WAIT_OBJECT_0;
}
__fastcall TMutex::TMutex(const AnsiString Name)
{
FHandle = CreateMutex(NULL, false, Name.c_str());
if (FHandle == 0) Abort();
}
bool __fastcall TMutex::Get(int TimeOut)
{
return WaitForSingleObject(FHandle, TimeOut) == WAIT_OBJECT_0;
}
bool __fastcall TMutex::Release(void)
{
return ReleaseMutex(FHandle);
}
__fastcall TSharedMem::TSharedMem(const AnsiString Name, int Size)
{
try{
FName = Name;
FSize = Size;
FHandle = CreateFileMapping((HANDLE)0xFFFFFFFF,
NULL,
PAGE_READWRITE,
0,
Size,
Name.c_str());
if (FHandle == 0) Abort();
FCreated = (GetLastError == 0);
FFileView = MapViewOfFile(FHandle,
FILE_MAP_WRITE,
0, 0, Size);
if (FFileView == NULL) Abort();
}
catch(...) {
Error(Format("Error creating shared memory %s (%d)",
(TVarRec*)Name.c_str(), GetLastError()));
}
}
__fastcall TSharedMem::~TSharedMem()
{
if (FFileView != NULL)
UnmapViewOfFile(FFileView);
}
#if defined(IPCDEBUG)
__fastcall TIPCTracer::TIPCTracer(AnsiString ID)
{
strcpy(FIDName, ID.c_str());
FSharedMem = new TSharedMem(TRACE_BUFFER, TRACE_BUF_SIZE);
FMutex = new TMutex(TRACE_MUTEX);
//The first four bytes of the buffer contain the number of meaningful
//bytes in the buffer at any given time.
if (*((int*)(FSharedMem->Buffer)) == 0)
*(int*)FSharedMem->Buffer = sizeof(PTraceEntry);
}
__fastcall TIPCTracer::~TIPCTracer()
{
delete FMutex;
delete FSharedMem;
}
PTraceEntry __fastcall TIPCTracer::MakePtr(int Ofs)
{
return PTraceEntry(int(FSharedMem->Buffer) + Ofs);
}
PTraceEntry __fastcall TIPCTracer::FirstEntry()
{
return MakePtr(sizeof(PTraceEntry));
}
PTraceEntry __fastcall TIPCTracer::NextEntry(void)
{
return MakePtr(*(int*)(FSharedMem->Buffer));
}
void __fastcall TIPCTracer::Add(PChar AMsg)
{
PTraceEntry TraceEntry;
int EntrySize;
TLargeInteger TempTime;
FMutex->Get(INFINITE);
TraceEntry = NextEntry();
EntrySize = sizeof(AMsg) + sizeof(TTraceEntry) + 16;
if ((EntrySize + *(int*)(FSharedMem->Buffer)) > FSharedMem->Size)
TraceEntry = FirstEntry();
QueryPerformanceCounter(&TempTime);
// TraceEntry->Time = TempTime.LowPart;
TraceEntry->Time = (int) TempTime.QuadPart;
TraceEntry->Size = EntrySize;
sprintf(TraceEntry->Msg,
"%s: %s", FIDName, AMsg);
*(int*)(FSharedMem->Buffer) = *(int*)(FSharedMem->Buffer) + TraceEntry->Size;
FMutex->Release();
}
void __fastcall TIPCTracer::GetList(TStrings *List)
{
PTraceEntry LastEntry;
PTraceEntry TraceEntry;
int Dif;
int LastTime;
List->BeginUpdate();
try{
LastEntry = NextEntry();
TraceEntry = FirstEntry();
LastTime = TraceEntry->Time;
List->Clear();
while (TraceEntry != LastEntry){
Dif = TraceEntry->Time - LastTime;
List->Add(Format("%x %10d %s",
ARRAYOFCONST((TraceEntry->Time,
Dif,
TraceEntry->Msg))));
LastTime = TraceEntry->Time;
(int)TraceEntry = (int)TraceEntry + TraceEntry->Size;
}
}
catch(...){
List->EndUpdate();
throw;
}
List->EndUpdate();
}
void __fastcall TIPCTracer::Clear()
{
FMutex->Get(INFINITE);
*(int*)FSharedMem->Buffer = sizeof(PTraceEntry);
FMutex->Release();
}
#endif
__fastcall TIPCEvent::TIPCEvent(TIPCThread *AOwner,
const AnsiString Name,
bool Manual)
:TEvent(Name, Manual)
{
FOwner = AOwner;
FSharedMem = new TSharedMem(Name, sizeof(TIPCEventInfo));
FEventInfo = (TIPCEventInfo*) FSharedMem->Buffer;
}
__fastcall TIPCEvent::~TIPCEvent()
{
delete FSharedMem;
}
int __fastcall TIPCEvent::GetID()
{
return FEventInfo->FID;
}
void __fastcall TIPCEvent::SetID(int Value)
{
FEventInfo->FID = Value;
}
TEventKind __fastcall TIPCEvent::GetKind()
{
return FEventInfo->FKind;
}
void __fastcall TIPCEvent::SetKind(TEventKind Value)
{
FEventInfo->FKind = Value;
}
TEventData __fastcall TIPCEvent::GetData()
{
return FEventInfo->FData;
}
void __fastcall TIPCEvent::SetData(const TEventData& Value)
{
FEventInfo->FData = Value;
}
void __fastcall TIPCEvent::Signal(TEventKind Kind)
{
SetID(OwnerID);
FEventInfo->FKind = Kind;
TEvent::Signal();
}
void __fastcall TIPCEvent::SignalID(TEventKind Kind, int ID)
{
FEventInfo->FID = ID;
FEventInfo->FKind = Kind;
TEvent::Signal();
}
void __fastcall TIPCEvent::SignalData(TEventKind Kind,
int ID,
const TEventData& Data)
{
FEventInfo->FID = ID;
FEventInfo->FData = Data;
FEventInfo->FKind = Kind;
TEvent::Signal();
}
bool __fastcall TIPCEvent::WaitFor(int TimeOut,
int ID,
TEventKind Kind)
{
bool returnval = Wait(TimeOut);
if (returnval)
returnval = (ID == FEventInfo->FID) && (Kind == FEventInfo->FKind);
else
FOwner->DbgStr(Format("Wait Failed %s Kind: %s ID: %x" ,
ARRAYOFCONST((FOwner->ClassName(),
EventName(Kind),
ID))));
return returnval;
}
__fastcall TClientDirectory::TClientDirectory(int MaxClients)
{
FMaxClients = MaxClients;
FMutex = new TMutex(CLIENT_DIR_MUTEX);
FSharedMem = new TSharedMem(CLIENT_DIR_NAME,
FMaxClients * sizeof(TClientDirEntry) + 8);
FMonitorID = (int*) FSharedMem->Buffer;
(int)FClientCount = (int)FMonitorID + sizeof(FMonitorID);
(int)FDirBuffer = (int)FClientCount + sizeof(FClientCount);
}
__fastcall TClientDirectory::~TClientDirectory()
{
delete FSharedMem;
}
int __fastcall TClientDirectory::AddClient(int ClientID, const AnsiString AName)
{
int Result = -1;
if (Count == FMaxClients)
{
String EString("Maximun of ");
EString += (int)FMaxClients;
EString += " clients allowed.";
Error(EString);
}
if (IndexOf(ClientID) > -1)
Error("Duplicate client ID");
if (FMutex->Get(TIMEOUT)){
try{
FDirBuffer[Count]->ID = ClientID;
lstrcpy(FDirBuffer[Count]->Name,
AName.c_str());
(*FClientCount)++;
Result = Count-1;
}
catch(...){
FMutex->Release();
throw;
} //end catch
} //end if (FMutex..
FMutex->Release();
return Result;
}
int __fastcall TClientDirectory::GetCount()
{
return (*FClientCount);
}
TClientDirEntry __fastcall TClientDirectory::GetClientRec(int Index)
{
if ((Index < 0) || (Index >= Count))
Error("Invalid client list index");
return *FDirBuffer[Index];
}
AnsiString __fastcall TClientDirectory::GetClientName(int ClientID)
{
int Index;
Index = IndexOf(ClientID);
if (Index >= 0)
return FDirBuffer[Index]->Name;
else
return "";
}
int __fastcall TClientDirectory::IndexOf(int ClientID)
{
int I;
for(I=0; I < Count; I++)
if (FDirBuffer[I]->ID == ClientID){
return I;
}
return -1;
}
int __fastcall TClientDirectory::Last()
{
if (Count > 0)
return FDirBuffer[Count-1]->ID;
else
return 0;
}
bool __fastcall TClientDirectory::RemoveClient(int ClientID)
{
int Index;
bool Result;
Index = IndexOf(ClientID);
if ((Index > -1) && FMutex->Get(TIMEOUT)){
try{
if ((Index > 0) && (Index < Count))
Move(FDirBuffer[Index+1],
FDirBuffer[Index],
(Count - Index) * sizeof(TClientDirEntry));
(*FClientCount)--; //Decrement client count
Result = true;
}
catch(...){
FMutex->Release();
throw;
}
FMutex->Release();
} //end if
else
Result = false;
return Result;
}
int __fastcall TClientDirectory::GetMonitorID()
{
return *FMonitorID;
}
void __fastcall TClientDirectory::SetMonitorID(int MonitorID)
{
*FMonitorID = MonitorID;
}
__fastcall TIPCThread::TIPCThread(int AID, const AnsiString AName)
:TThread(true)
{
FID = AID;
FName = AName;
#if defined(IPCDEBUG)
if (dynamic_cast
FTracer = new TIPCTracer(FName);
else
FTracer = new TIPCTracer(IntToHex(FID, 8));
#endif
FMonitorEvent = new TIPCEvent(this, MONITOR_EVENT_NAME, false);
FClientEvent = new TIPCEvent(this, CLIENT_EVENT_NAME, false);
FConnectEvent = new TIPCEvent(this, CONNECT_EVENT_NAME, false);
FClientDirectory = new TClientDirectory(MAX_CLIENTS);
}
__fastcall TIPCThread::~TIPCThread()
{
DeActivate();
delete FClientDirectory;
delete FClientEvent;
delete FMonitorEvent;
FState = stInActive;
#if defined(IPCDEBUG)
delete FTracer;
#endif
}
void __fastcall TIPCThread::DbgStr(const AnsiString S)
{
#if defined(IPCDEBUG)
FTracer->Add(S.c_str());
#endif
}
__fastcall TIPCMonitor::TIPCMonitor(int AID, const AnsiString AName)
: TIPCThread(AID, AName),
FAutoSwitch(true)
{
}
void __fastcall TIPCMonitor::Activate()
{
if (FState == stInActive) {
// Put the monitor handle into the client directory so we can use it to
// prevent multiple monitors from running
if (FClientDirectory->MonitorID == 0)
FClientDirectory->MonitorID = FID;
else
throw EMonitorActive("Monitor is already active.");
FState = stDisconnected;
Resume();
}
}
void __fastcall TIPCMonitor::DeActivate()
{
if ((State != stInActive) && !(Suspended)){
FClientDirectory->MonitorID = 0;
FMonitorEvent->Signal(evMonitorExit);
if (WaitForSingleObject((void *)Handle, TIMEOUT) != WAIT_OBJECT_0)
TerminateThread((void *)Handle, 0);
}
}
void __fastcall TIPCMonitor::Execute()
{
int WaitResult;
bool bContinueThread = true;
DbgStr(FName + " Activated");
if (FClientDirectory->Count > 0)
FMonitorEvent->SignalID(evClientStart, FClientDirectory->Last());
while (bContinueThread == true){
try {
WaitResult = WaitForSingleObject(FMonitorEvent->Handle, INFINITE);
if (WaitResult >= WAIT_ABANDONED)
DisconnectFromClient(false);
else{
if (WaitResult == WAIT_OBJECT_0)
{
DbgStr("Event Signaled: " + EventName(FMonitorEvent->Kind));
switch (FMonitorEvent->Kind){
case evClientSignal:
DoOnSignal();
break;
case evClientStart:
if ((AutoSwitch == true) || (FClientID == 0))
ConnectToClient(FMonitorEvent->ID);
DoOnDirUpdate();
break;
case evClientStop:
DoOnDirUpdate();
break;
case evClientDetach:
DisconnectFromClient(false);
Sleep(100);
if (AutoSwitch != false)
ConnectToClient(FClientDirectory->Last());
break;
case evClientSwitch:
ConnectToClient(FMonitorEvent->ID);
break;
case evMonitorExit:
DisconnectFromClient(false);
bContinueThread = false;
break;
default:
break;
} //end switch
} //end if
else {
DbgStr(Format("Unexpected Wait Return Code: %d",
ARRAYOFCONST((WaitResult))));
} //end else
} //end else
} //end try
catch(Exception& E){
DbgStr(Format("Exception raised in Thread Handler: %s at %X",
ARRAYOFCONST((E.Message, ExceptAddr))));
} //end catch
}//end while
FState = stInActive;
DbgStr("Thread Handler Exited");
}
void __fastcall TIPCMonitor::ConnectToClient(int ID)
{
if (ID == FClientID) return;
if (FState == stConnected)
DisconnectFromClient(true);
if (ID == 0) return;
DbgStr(Format("Sending evMonitorAttach: %X",
ARRAYOFCONST((ID))));
FConnectEvent->SignalID(evMonitorAttach, ID);
if ((FMonitorEvent->WaitFor(TIMEOUT, ID, evClientAttach) != false) &&
(FMonitorEvent->Data.Flag == cfAttach)) {
FClientID = ID;
FState = stConnected;
if (FOnConnect != NULL)
OnConnect(this, true);
DbgStr("ConnectToClient Successful");
}
else
DbgStr("ConnectToClient Failed: " + EventName(FMonitorEvent->Kind));
}
void __fastcall TIPCMonitor::DisconnectFromClient(bool Wait)
{
if (FState == stConnected){
DbgStr(Format("Sending evMonitorDetach: %x",
ARRAYOFCONST((FClientID))));
FClientEvent->SignalID(evMonitorDetach, FClientID);
if (Wait)
if (FMonitorEvent->WaitFor(TIMEOUT, FClientID, evClientDetach) == 0){
DbgStr(Format("Error waiting for client to detach: %x",
ARRAYOFCONST((FClientID))));
FClientDirectory->RemoveClient(FClientID);
}
FClientID = 0;
FState = stDisconnected;
if (FOnConnect != 0)
FOnConnect(this, false);
if ((! Wait) && (FOnDirUpdate != NULL))
DoOnDirUpdate();
}
}
void __fastcall TIPCMonitor::DoOnSignal(void)
{
if ((FOnSignal != NULL) && (FMonitorEvent->ID == FClientID))
FOnSignal(this, FMonitorEvent->Data);
}
void __fastcall TIPCMonitor::SignalClient(const TClientFlags Value)
{
if (FState == stConnected){
FClientEvent->EventInfo->FData.Flags = Value;
DbgStr("Signaling Client");
FClientEvent->SignalData(evMonitorSignal, FClientID, FClientEvent->Data);
}
}
AnsiString __fastcall TIPCMonitor::GetClientName()
{
return FClientDirectory->Name[FClientID];
}
void __fastcall TIPCMonitor::GetClientNames(TStringList* List)
{
int I;
AnsiString S;
int DupCnt;
List->BeginUpdate();
try{
List->Clear();
for(I=0; I < FClientDirectory->Count; I++){
S = FClientDirectory->ClientRec[I].Name;
DupCnt = 1;
while(List->IndexOf(S) > -1){
DupCnt++;
S = Format("%s (%d)",
ARRAYOFCONST((FClientDirectory->ClientRec[I].Name,
DupCnt)));
}
List->AddObject(S, (TObject*)FClientDirectory->ClientRec[I].ID);
}
}
catch(...){
List->EndUpdate();
throw;
}
List->EndUpdate();
}
void __fastcall TIPCMonitor::SetCurrentClient(int ID)
{
if (ID == 0)
ID = FClientDirectory->Last();
if (ID !=0)
FMonitorEvent->SignalID(evClientSwitch, ID);
}
void __fastcall TIPCMonitor::ClearDebugInfo()
{
#ifdef IPCDEBUG
FTracer->Clear();
#endif
}
void __fastcall TIPCMonitor::GetDebugInfo(TStrings *List)
{
#ifdef IPCDEBUG
FTracer->GetList(List);
#else
List->Add("Debug Tracing Disabled");
#endif
}
void __fastcall TIPCMonitor::SaveDebugInfo(const AnsiString FileName)
{
#if defined(IPCDEBUG)
TStringList* List;
List = new TStringList();
try{
GetDebugInfo(List);
List->SaveToFile(FileName);
}
catch(...){
delete List;
throw;
}
delete List;
#endif
}
void __fastcall TIPCMonitor::DoOnDirUpdate()
{
if (FOnDirUpdate != NULL)
FOnDirUpdate(this);
}
void __fastcall TIPCClient::Activate()
{
if (FState == stInActive){
FWaitEvent = FConnectEvent;
FMonitorEvent->OwnerID = FID;
FConnectEvent->OwnerID = FID;
FClientEvent->OwnerID = FID;
FClientDirectory->AddClient(FID, FName);
FState = stDisconnected;
Resume();
}
}
void __fastcall TIPCClient::DeActivate()
{
if (FClientDirectory != NULL)
FClientDirectory->RemoveClient(FID);
if ((FState != stInActive) && !(Suspended)){
FWaitEvent->Signal(evClientExit);
if (WaitForSingleObject((void *)Handle, TIMEOUT) != WAIT_OBJECT_0)
TerminateThread((void *)Handle, 0);
}
}
void __fastcall TIPCClient::Execute(void)
{
DbgStr(FName + " Activated");
bool bContinueThread = true;
if ((FClientDirectory->MonitorID) != 0)
{
FMonitorEvent->SignalID(evClientStart, FID);
}
while (bContinueThread == true){
try{
if (WaitForSingleObject(FWaitEvent->Handle, INFINITE) != WAIT_OBJECT_0)
break;
if (FWaitEvent->ID != FID){
Sleep(200);
continue;
}
DbgStr("Client Event Signaled: " + EventName(FWaitEvent->Kind));
switch(FWaitEvent->Kind){
case evMonitorSignal:
if (FOnSignal != NULL)
FOnSignal(this, FWaitEvent->Data);
break;
case evMonitorAttach:
ConnectToMonitor();
break;
case evMonitorDetach:
DisconnectFromMonitor(false);
Sleep(200);
break;
case evClientExit:
if (FClientDirectory->MonitorID != 0) {
if (FState == stConnected)
DisconnectFromMonitor(true);
else
FMonitorEvent->Signal(evClientStop);
}
bContinueThread = false;
break;
default:
break;
} //end switch
} //end try
catch(Exception& E){
DbgStr(Format("Exception raised in Thread Handler: %s at %X",
ARRAYOFCONST((E.Message, ExceptAddr))));
}//end try-catch
} //end while
FState = stInActive;
DbgStr("Thread Handler Exited");
}
void __fastcall TIPCClient::ConnectToMonitor()
{
TEventData Data;
DbgStr("ConnectToMonitor Begin");
FConnectEvent->Reset();
try {
FState = stConnected;
FWaitEvent = FClientEvent;
Data.Flag = cfAttach;
FMonitorEvent->SignalData(evClientAttach, FID, Data);
if (FOnConnect != 0)
FOnConnect(this, true);
}
catch(Exception& E){
DbgStr("Exception in ConnectToMonitor: " + E.Message);
Data.Flag = cfError;
FMonitorEvent->SignalData(evClientAttach, FID, Data);
}
DbgStr("ConnectToMonitor End");
}
void __fastcall TIPCClient::DisconnectFromMonitor(bool Wait)
{
DbgStr("DisconnectFromMonitor Begin");
if (FState == stConnected) {
if (Wait){
DbgStr("Sending evClientDetach");
FMonitorEvent->Signal(evClientDetach);
if (FClientEvent->WaitFor(TIMEOUT, FID, evMonitorDetach))
DbgStr("Got evMonitorDetach");
else
DbgStr("Error waiting for evMonitorDetach");
}
FState = stDisconnected;
FWaitEvent = FConnectEvent;
if (! Wait){
DbgStr("DisconnectFromMonitor sending evClientDetach");
FMonitorEvent->Signal(evClientDetach);
}
if (FOnConnect != NULL)
FOnConnect((TIPCThread*)this, false);
}
DbgStr("DisconnectFromMonitor End");
}
void __fastcall TIPCClient::SignalMonitor(const TEventData& Data)
{
if (FState == stConnected){
DbgStr("Signaling Monitor");
FMonitorEvent->SignalData(evClientSignal, FID, Data);
}
}
int __fastcall TIPCClient::ClientCount()
{
return FClientDirectory->Count;
}
void __fastcall TIPCClient::MakeCurrent()
{
FMonitorEvent->SignalID(evClientStart, FID);
}
//---------------------------------------------------------------------------
#include "about.h"
//---------------------------------------------------------------------------
#pragma resource "*.dfm"
TAboutBox *AboutBox;
__fastcall TAboutBox::TAboutBox(TComponent* Owner) : TForm(Owner)
{
}
void __fastcall TAboutBox::FormCreate(TObject *Sender)
{
Caption = Format("About %s",
ARRAYOFCONST((Application->Title)));
ProgramIcon->Picture->Assign(Application->Icon);
ProgramName->Caption = Application->Title;
}
void __fastcall ShowAboutBox()
{
TAboutBox* a = new TAboutBox(Application);
try{
a->ShowModal();
}
catch(...){
a->Free();
throw;
}
a->Free();
}
//-----------------------------------------------------------------------------
#include "TrcView.h"
//-----------------------------------------------------------------------------
#pragma resource "*.DFM"
TTraceForm* TraceForm;
__fastcall TTraceForm::TTraceForm(TComponent* Owner) : TForm(Owner)
{
}
void __fastcall TTraceForm::TraceDataKeyPress( TObject* Sender, Char& Key)
{
if (Key == 0x27) Close();
}



