home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1997 April
/
Chip_1997-04_cd.bin
/
prezent
/
cb
/
data.z
/
IBCTRLS.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1997-01-16
|
12KB
|
477 lines
//---------------------------------------------------------------------------
// Borland C++Builder
// Copyright (c) 1987, 1996 Borland International Inc. All Rights Reserved.
//---------------------------------------------------------------------------
// ibctrls.cpp
// This file is #included in IBREG.CPP which #includes IBREG.H which
// in turn #includes IBCTRLS.H. Hence #including IBCTRLS.H here is redundant with
// no ramifications (there are sentries in the header file) but has been done
// just to clarify that the function and class implementations in this file are
// prototyped in IBCTRLS.H
#include "ibctrls.h"
//---------------------------------------------------------------------------
// Dynamically Loaded InterBase API functions (gds32.dll)
TIscQueEvents IscQueEvents;
TIscFree IscFree;
TIscEventBlock IscEventBlock;
TIscEventCounts IscEventCounts;
TIscCancelEvents IscCancelEvents;
TIscInterprete IscInterprete;
// TIBComponent class implementation
Pointer __fastcall TIBComponent::GetNativeHandle(void)
{
int length = 0;
isc_db_handle result = NULL;
if( FDatabase != NULL && FDatabase->Connected )
Check( DbiGetProp( (hDBIObj)FDatabase->Handle, dbNATIVEHNDL,
&result, sizeof( isc_db_handle), length ) );
else
result = NULL;
return result;
}
void __fastcall TIBComponent::HandleIBErrors(Ibproc32::pstatus_vector status)
{
char buffer[255];
AnsiString errMsg = "";
AnsiString lastMsg;
isc_status errCode;
do
{
errCode = IscInterprete( buffer, &status);
if( lastMsg != AnsiString( buffer) )
{
lastMsg = AnsiString( buffer);
if( errMsg.Length() != 0 )
errMsg = errMsg+"\n";
errMsg = errMsg+lastMsg;
}
} while( errCode != 0 );
throw EIBError( errMsg );
}
bool __fastcall TIBComponent::IsInterbaseDatabase(Db::TDatabase *Database)
{
bool Result;
int Length=0;
char Buffer[63];
Result = false;
if( Database->Handle != NULL )
{
Check(DbiGetProp(hDBIObj(Database->Handle), dbDATABASETYPE, Buffer,
sizeof(Buffer), Length));
Result = ( stricmp(Buffer, "INTRBASE" ) == 0 );
}
return Result;
}
void __fastcall TIBComponent::SetDatabase(Db::TDatabase *value)
{
if( value != FDatabase )
{
if( value != NULL && value->Connected )
ValidateDatabase( value );
FDatabase = value;
}
}
void __fastcall TIBComponent::ValidateDatabase(Db::TDatabase *Database)
{
if( Database == NULL || !Database->Connected )
throw EIBError( SInvalidDBConnection );
else
{
if( !IsInterbaseDatabase( Database) )
throw EIBError( SInvalidDatabase, new TVarRec( Database->Name ), 1 );
}
}
__stdcall HandleEvent( int param )
{
// don't let exceptions propogate out of thread
try
{
//!! TIBEventAlerter( param )->HandleEvent;
//!! TIBEventAlerter(this).HandleEvent();
TIBEventAlerter(NULL).HandleEvent();
}
//except
catch(...)
{
// Application.HandleException( nil);
Application->HandleException( NULL );
}
return 0;
}
#pragma warn -rvl
__cdecl IBEventCallback( Pointer ptr, short length, PChar updated )
{
int ThreadID=0;
// Handle events asynchronously in second thread
EnterCriticalSection(&TIBEventAlerter(NULL).CS );
TIBEventAlerter( NULL).UpdateResultBuffer( length, updated);
CloseHandle( CreateThread( (LPSECURITY_ATTRIBUTES)NULL, (DWORD)8192, (LPTHREAD_START_ROUTINE)HandleEvent,
(LPVOID)ptr, (DWORD)0, (LPDWORD)ThreadID) );
LeaveCriticalSection( &(TIBEventAlerter( NULL ).CS));
}
#pragma warn .rvl
__fastcall TIBEventAlerter::TIBEventAlerter( TComponent* AOwner ):TIBComponent( AOwner )
{
InitializeCriticalSection(&CS);
FEvents = new TStringList; //.Create;
((TStringList*)FEvents)->OnChange = EventChange;
((TStringList*)FEvents)->Duplicates = dupIgnore;
// Attempt to load GDS32.DLL. If this fails then raise an exception.
// This will cause the component not to be created
LibHandle = (int) LoadLibrary("gds32.dll");
if( LibHandle < 32 ) //then
throw( EDLLLoadError("Unable to load gds32.dll") );
IscQueEvents = (TIscQueEvents)GetProcAddress((HINSTANCE)LibHandle, "isc_que_events");
if( IscQueEvents == NULL ) // then // !!must initialize to NULL?
throw( EDLLLoadError("Failed to lookup isc_que_events") );
IscInterprete = (TIscInterprete)GetProcAddress((HINSTANCE)LibHandle, "isc_interprete");
if( IscInterprete == NULL ) // nil then
throw EDLLLoadError("Failed to lookup isc_interprete");
IscFree = (TIscFree)GetProcAddress((HINSTANCE)LibHandle, "isc_free");
if( IscFree == NULL ) //nil then
throw EDLLLoadError("Failed to lookup isc_free");
IscEventBlock = (TIscEventBlock) GetProcAddress((HINSTANCE)LibHandle, "isc_event_block");
if( IscEventBlock == NULL ) // nil then
throw EDLLLoadError("Failed to lookup isc_event_block");
IscEventCounts = (TIscEventCounts )GetProcAddress((HINSTANCE)LibHandle, "isc_event_counts");
if( IscEventCounts == NULL ) // nil then
throw EDLLLoadError("Failed to lookup isc_event_counts");
IscCancelEvents = (TIscCancelEvents) GetProcAddress((HINSTANCE)LibHandle, "isc_cancel_events");
if( IscCancelEvents == NULL ) // nil then
throw EDLLLoadError("Failed to lookup isc_cancel_events");
}
__fastcall TIBEventAlerter::~TIBEventAlerter(void)
{
UnRegisterEvents();
SetDatabase(NULL);
((TStringList*)FEvents)->OnChange = NULL;
delete FEvents;
DeleteCriticalSection( &CS);
if( LibHandle >= 32 ) //then
FreeLibrary((HINSTANCE)LibHandle);
}
void __fastcall TIBEventAlerter::CancelEvents(void)
{
status_vector status;
isc_status errCode;
isc_db_handle dbHandle;
if( ProcessingEvents )
throw EIBError(SInvalidCancellation);
if( FQueued )
{
try
{
// wait for event handler to finish before cancelling events
EnterCriticalSection(&CS);
ValidateDatabase( Database);
FQueued = false;
Changing = true;
dbHandle = GetNativeHandle();
errCode = IscCancelEvents( &status, &dbHandle, &EventID);
if( errCode != 0 )
HandleIBErrors( &status );
LeaveCriticalSection(&CS);
}
catch( ... ){
LeaveCriticalSection(&CS);
throw;
} // !!end finally
} // end Fqued
}
void __fastcall TIBEventAlerter::DoQueueEvents(void)
{
status_vector status;
isc_status errCode;
Pointer callback;
isc_db_handle dbHandle;
ValidateDatabase( Database);
callback = IBEventCallback;
dbHandle = GetNativeHandle();
errCode = IscQueEvents( &status, &dbHandle, &EventID, EventBufferLen,
EventBuffer, isc_callback(callback), this);
if( errCode != 0 )
HandleIBErrors( &status);
FQueued = true;
}
void __fastcall TIBEventAlerter::EventChange(System::TObject *sender)
{
// check for blank event
if( ((TStringList*)Events)->IndexOf("") != -1 )
throw EIBError( SInvalidEvent);
// check for too many events
if( Events->Count > MaxEvents ) //then
{
((TStringList*)Events)->OnChange = NULL;
Events->Delete( MaxEvents);
((TStringList*)Events)->OnChange = EventChange;
throw EIBError(SMaximumEvents);
}
if( Registered )
RegisterEvents();
}
void __fastcall TIBEventAlerter::HandleEvent(void)
{
bool CancelAlerts;
int i;
status_vector status;
try
{
// prevent modification of vital data structures while handling events
EnterCriticalSection(&CS);
ProcessingEvents = true;
IscEventCounts( &status, EventBufferLen, EventBuffer, ResultBuffer);
CancelAlerts = false;
if( FOnEventAlert != NULL && !Changing )
{
for( i = 0; i < Events->Count; i++ ) // do
{
try
{
if(status[i] != 0 && !CancelAlerts ) //then
FOnEventAlert( this,
Events->Strings[Events->Count-i-1],
status[i],
CancelAlerts);
}
catch(...) //except
{
Application->HandleException( NULL);
}
}
}
Changing = false;
if( !CancelAlerts && FQueued ) //then
DoQueueEvents();
} // end try
catch(...)
{
ProcessingEvents = false;
LeaveCriticalSection(&CS);
throw;
} // end finally?
}
void __fastcall TIBEventAlerter::Loaded(void)
{
TIBComponent::Loaded();
try
{
if( RegisteredState ) //then
RegisterEvents();
}
catch(...)// except
{
if( ComponentState.Contains( csDesigning ) )
Application->HandleException( this );
else
throw;
}
}
void __fastcall TIBEventAlerter::Notification(Classes::TComponent *AComponent, Classes::TOperation Operation )
{
TIBComponent::Notification( AComponent, Operation);
if( Operation == opRemove && AComponent == Database)// then
{
UnRegisterEvents();
Database = NULL;
}
}
void __fastcall TIBEventAlerter::QueueEvents(void)
{
if( !FRegistered ) //then
throw EIBError( SNoEventsRegistered);
if( ProcessingEvents ) //then
throw EIBError( SInvalidQueueing);
if( !FQueued ) //then
{
try
// wait until current event handler is finished before queuing events
{
EnterCriticalSection( &CS);
DoQueueEvents();
Changing = true;
LeaveCriticalSection( &CS);
}
catch(...)
{
LeaveCriticalSection( &CS);
throw;
}
}
}
void __fastcall TIBEventAlerter::RegisterEvents(void)
{
ValidateDatabase( Database);
if( ComponentState.Contains( csDesigning ) )
FRegistered = true;
else
{
UnRegisterEvents();
if( Events->Count == 0 )
return;
for(int i = 0; i < Events->Count; i++ )
strcpy( Buffer[i], Events->Strings[i].c_str());
EventBufferLen = IscEventBlock(EventBuffer,
ResultBuffer,
Events->Count,
Buffer[0]);
/*
asm
{
mov ecx, dword ptr [i]
mov eax, dword ptr [bufptr]
@@1:
push eax
add eax, EventLength
loop @@1
push dword ptr [i]
push dword ptr [resultBufPtr]
push dword ptr [eventBufPtr]
call [IscEventBlock]
mov dword ptr [buflen], eax
mov eax, dword ptr [i]
shl eax, 2
add eax, 12
add esp, eax
}*/ // end asm block
FRegistered = true;
QueueEvents();
}
}
void __fastcall TIBEventAlerter::SetEvents(Classes::TStrings *value)
{
FEvents->Assign( value);
}
void __fastcall TIBEventAlerter::SetDatabase(Db::TDatabase *value)
{
if( value != Database )
{
UnRegisterEvents();
if( value != NULL && value->Connected ) //!!assigned?
ValidateDatabase( value);
Database = value;
}
}
void __fastcall TIBEventAlerter::SetRegistered( bool value )
{
if( ComponentState.Contains ( csReading ) )
RegisteredState = value;
else
if( FRegistered != value )
if( value )
RegisterEvents();
else
UnRegisterEvents();
}
void __fastcall TIBEventAlerter::UnRegisterEvents(void)
{
if( ProcessingEvents )
throw EIBError( SInvalidRegistration);
if( ComponentState.Contains( csDesigning ) )
FRegistered = false;
else
if( ComponentState.Contains( csLoading ) != true )
{
CancelEvents();
if( FRegistered )
{
IscFree( EventBuffer);
EventBuffer = NULL;
IscFree( ResultBuffer);
ResultBuffer = NULL;
}
FRegistered = false;
}
}
void __fastcall TIBEventAlerter::UpdateResultBuffer(int length, System::PChar updated)
{
int i;
for( i = 0; i< length; i++ )
ResultBuffer[i] = updated[i];
}