home *** CD-ROM | disk | FTP | other *** search
/ Chip 1997 April / Chip_1997-04_cd.bin / prezent / cb / data.z / IBCTRLS.CPP < prev    next >
C/C++ Source or Header  |  1997-01-16  |  12KB  |  477 lines

  1. //---------------------------------------------------------------------------
  2. // Borland C++Builder
  3. // Copyright (c) 1987, 1996 Borland International Inc.  All Rights Reserved.
  4. //---------------------------------------------------------------------------
  5. // ibctrls.cpp
  6. // This file is #included in IBREG.CPP which #includes IBREG.H which
  7. // in turn #includes IBCTRLS.H.  Hence #including IBCTRLS.H here is redundant with
  8. // no ramifications (there are sentries in the header file) but has been done
  9. // just to clarify that the function and class implementations in this file are
  10. // prototyped in IBCTRLS.H
  11. #include "ibctrls.h"
  12.  
  13. //---------------------------------------------------------------------------
  14. // Dynamically Loaded InterBase API functions (gds32.dll)
  15. TIscQueEvents IscQueEvents;
  16. TIscFree IscFree;
  17. TIscEventBlock IscEventBlock;
  18. TIscEventCounts IscEventCounts;
  19. TIscCancelEvents IscCancelEvents;
  20. TIscInterprete IscInterprete;
  21.  
  22. // TIBComponent class implementation
  23.  
  24. Pointer __fastcall TIBComponent::GetNativeHandle(void)
  25. {
  26.   int length = 0;
  27.   isc_db_handle result = NULL;
  28.   if( FDatabase != NULL  && FDatabase->Connected )
  29.       Check( DbiGetProp( (hDBIObj)FDatabase->Handle, dbNATIVEHNDL,
  30.                         &result, sizeof( isc_db_handle), length ) );
  31.   else
  32.     result = NULL;
  33.  return result;
  34.  }
  35.  
  36.  
  37. void __fastcall TIBComponent::HandleIBErrors(Ibproc32::pstatus_vector status)
  38. {
  39.  
  40.   char buffer[255];
  41.   AnsiString errMsg = "";
  42.   AnsiString lastMsg;
  43.   isc_status errCode;
  44.  
  45.   do
  46.   {
  47.     errCode = IscInterprete( buffer, &status);
  48.     if( lastMsg != AnsiString( buffer) )
  49.     {
  50.       lastMsg = AnsiString( buffer);
  51.       if( errMsg.Length() !=  0 )
  52.         errMsg = errMsg+"\n";
  53.       errMsg = errMsg+lastMsg;
  54.     }
  55.   } while( errCode != 0 );
  56.   throw EIBError( errMsg );
  57. }
  58.  
  59.  
  60.  
  61.  
  62. bool __fastcall TIBComponent::IsInterbaseDatabase(Db::TDatabase *Database)
  63. {
  64.   bool Result;
  65.   int Length=0;
  66.   char Buffer[63];
  67.  
  68.   Result = false;
  69.   if( Database->Handle != NULL )
  70.   {
  71.     Check(DbiGetProp(hDBIObj(Database->Handle), dbDATABASETYPE, Buffer,
  72.       sizeof(Buffer), Length));
  73.     Result = ( stricmp(Buffer, "INTRBASE" ) == 0 );
  74.   }
  75.   return Result;
  76. }
  77.  
  78.  
  79.  
  80.  
  81.  
  82. void __fastcall TIBComponent::SetDatabase(Db::TDatabase *value)
  83. {
  84.   if( value != FDatabase )
  85.   {
  86.     if( value != NULL && value->Connected )
  87.         ValidateDatabase( value );
  88.     FDatabase = value;
  89.   }
  90. }
  91.  
  92.  
  93.  
  94.  
  95. void __fastcall TIBComponent::ValidateDatabase(Db::TDatabase *Database)
  96. {
  97.   if( Database == NULL  || !Database->Connected  )
  98.           throw EIBError( SInvalidDBConnection );
  99.   else
  100.   {
  101.    if( !IsInterbaseDatabase( Database)  )
  102.     throw EIBError( SInvalidDatabase, new TVarRec( Database->Name ), 1 );
  103.   }
  104. }
  105.  
  106.  
  107.  
  108. __stdcall HandleEvent( int param )
  109. {
  110.   // don't let exceptions propogate out of thread
  111.   try
  112.   {
  113.   //!!    TIBEventAlerter( param )->HandleEvent;
  114.   //!!    TIBEventAlerter(this).HandleEvent();
  115.       TIBEventAlerter(NULL).HandleEvent();
  116.   }
  117.   //except
  118.   catch(...)
  119.   {
  120.   // Application.HandleException( nil);
  121.     Application->HandleException( NULL );
  122.   }
  123.   return 0;
  124. }
  125.  
  126.  
  127.  
  128. #pragma warn -rvl
  129. __cdecl IBEventCallback( Pointer ptr, short length, PChar updated )
  130. {
  131.   int ThreadID=0;
  132.   // Handle events asynchronously in second thread
  133.   EnterCriticalSection(&TIBEventAlerter(NULL).CS );
  134.   TIBEventAlerter( NULL).UpdateResultBuffer( length, updated);
  135.   CloseHandle( CreateThread( (LPSECURITY_ATTRIBUTES)NULL, (DWORD)8192, (LPTHREAD_START_ROUTINE)HandleEvent,
  136.        (LPVOID)ptr, (DWORD)0, (LPDWORD)ThreadID) );
  137.   LeaveCriticalSection( &(TIBEventAlerter( NULL ).CS));
  138.  }
  139. #pragma warn .rvl
  140.  
  141.  
  142.  
  143.  
  144.  
  145. __fastcall TIBEventAlerter::TIBEventAlerter( TComponent* AOwner ):TIBComponent( AOwner )
  146. {
  147.   InitializeCriticalSection(&CS);
  148.   FEvents = new TStringList; //.Create;
  149.   ((TStringList*)FEvents)->OnChange = EventChange;
  150.   ((TStringList*)FEvents)->Duplicates = dupIgnore;
  151.  
  152.   // Attempt to load GDS32.DLL.  If this fails then raise an exception.
  153.   // This will cause the component not to be created
  154.   LibHandle = (int) LoadLibrary("gds32.dll");
  155.   if( LibHandle < 32 ) //then
  156.       throw( EDLLLoadError("Unable to load gds32.dll") );
  157.   IscQueEvents = (TIscQueEvents)GetProcAddress((HINSTANCE)LibHandle, "isc_que_events");
  158.   if( IscQueEvents == NULL ) // then            // !!must initialize to NULL?
  159.       throw( EDLLLoadError("Failed to lookup isc_que_events") );
  160.   IscInterprete = (TIscInterprete)GetProcAddress((HINSTANCE)LibHandle, "isc_interprete");
  161.   if( IscInterprete == NULL ) // nil then
  162.       throw EDLLLoadError("Failed to lookup isc_interprete");
  163.  
  164.   IscFree = (TIscFree)GetProcAddress((HINSTANCE)LibHandle, "isc_free");
  165.   if( IscFree ==  NULL ) //nil then
  166.     throw EDLLLoadError("Failed to lookup isc_free");
  167.  
  168.   IscEventBlock = (TIscEventBlock) GetProcAddress((HINSTANCE)LibHandle, "isc_event_block");
  169.   if( IscEventBlock == NULL ) // nil then
  170.      throw EDLLLoadError("Failed to lookup isc_event_block");
  171.  
  172.   IscEventCounts = (TIscEventCounts )GetProcAddress((HINSTANCE)LibHandle, "isc_event_counts");
  173.   if( IscEventCounts == NULL ) // nil then
  174.      throw EDLLLoadError("Failed to lookup isc_event_counts");
  175.  
  176.   IscCancelEvents = (TIscCancelEvents) GetProcAddress((HINSTANCE)LibHandle, "isc_cancel_events");
  177.   if( IscCancelEvents == NULL ) // nil then
  178.       throw EDLLLoadError("Failed to lookup isc_cancel_events");
  179.   }
  180.  
  181.  
  182. __fastcall TIBEventAlerter::~TIBEventAlerter(void)
  183. {
  184.   UnRegisterEvents();
  185.   SetDatabase(NULL);
  186.   ((TStringList*)FEvents)->OnChange = NULL;
  187.   delete FEvents;
  188.   DeleteCriticalSection( &CS);
  189.   if( LibHandle >= 32 ) //then
  190.     FreeLibrary((HINSTANCE)LibHandle);
  191. }
  192.  
  193.  
  194. void __fastcall TIBEventAlerter::CancelEvents(void)
  195. {
  196.   status_vector status;
  197.   isc_status errCode;
  198.   isc_db_handle dbHandle;
  199.  
  200.   if( ProcessingEvents )
  201.       throw EIBError(SInvalidCancellation);
  202.   if( FQueued )
  203.   {
  204.     try
  205.     {
  206.       // wait for event handler to finish before cancelling events
  207.       EnterCriticalSection(&CS);
  208.       ValidateDatabase( Database);
  209.       FQueued = false;
  210.       Changing = true;
  211.       dbHandle = GetNativeHandle();
  212.       errCode = IscCancelEvents( &status, &dbHandle, &EventID);
  213.       if( errCode != 0 )
  214.          HandleIBErrors( &status );
  215.       LeaveCriticalSection(&CS);
  216.     }
  217.     catch( ... ){
  218.       LeaveCriticalSection(&CS);
  219.       throw;
  220.     } //   !!end finally
  221.   } // end Fqued
  222. }
  223.  
  224.  
  225.  
  226.  
  227.  
  228. void __fastcall TIBEventAlerter::DoQueueEvents(void)
  229. {
  230.   status_vector status;
  231.   isc_status errCode;
  232.   Pointer callback;
  233.   isc_db_handle dbHandle;
  234.  
  235.   ValidateDatabase( Database);
  236.   callback = IBEventCallback;
  237.   dbHandle = GetNativeHandle();
  238.   errCode = IscQueEvents( &status, &dbHandle, &EventID, EventBufferLen,
  239.                           EventBuffer, isc_callback(callback), this);
  240.   if( errCode != 0 )
  241.     HandleIBErrors( &status);
  242.   FQueued = true;
  243.  }
  244.  
  245.  
  246.  
  247. void __fastcall TIBEventAlerter::EventChange(System::TObject *sender)
  248. {
  249.  // check for blank event
  250.  if( ((TStringList*)Events)->IndexOf("") !=  -1 )
  251.      throw EIBError( SInvalidEvent);
  252.   // check for too many events
  253.  if( Events->Count > MaxEvents ) //then
  254.  {
  255.     ((TStringList*)Events)->OnChange = NULL;
  256.     Events->Delete( MaxEvents);
  257.     ((TStringList*)Events)->OnChange = EventChange;
  258.     throw EIBError(SMaximumEvents);
  259.  }
  260.  if( Registered )
  261.      RegisterEvents();
  262. }
  263.  
  264.  
  265.  
  266. void __fastcall TIBEventAlerter::HandleEvent(void)
  267. {
  268.   bool CancelAlerts;
  269.   int i;
  270.   status_vector status;
  271.   try
  272.   {
  273.     // prevent modification of vital data structures while handling events
  274.     EnterCriticalSection(&CS);
  275.     ProcessingEvents = true;
  276.     IscEventCounts( &status, EventBufferLen, EventBuffer, ResultBuffer);
  277.     CancelAlerts = false;
  278.     if( FOnEventAlert != NULL && !Changing )
  279.     {
  280.        for( i = 0; i < Events->Count; i++ ) // do
  281.        {
  282.          try
  283.          {
  284.            if(status[i] != 0 && !CancelAlerts ) //then
  285.              FOnEventAlert( this,
  286.                             Events->Strings[Events->Count-i-1],
  287.                             status[i],
  288.                             CancelAlerts);
  289.          }
  290.          catch(...) //except
  291.          {
  292.            Application->HandleException( NULL);
  293.          }
  294.        }
  295.     }
  296.     Changing = false;
  297.     if( !CancelAlerts && FQueued ) //then
  298.         DoQueueEvents();
  299.   } //  end try
  300.   catch(...)
  301.   {
  302.     ProcessingEvents = false;
  303.     LeaveCriticalSection(&CS);
  304.     throw;
  305.   }  //  end finally?
  306. }
  307.  
  308.  
  309.  
  310. void __fastcall TIBEventAlerter::Loaded(void)
  311. {
  312.   TIBComponent::Loaded();
  313.   try
  314.   {
  315.    if( RegisteredState ) //then
  316.      RegisterEvents();
  317.    }
  318.   catch(...)//  except
  319.   {
  320.     if( ComponentState.Contains( csDesigning ) )
  321.       Application->HandleException( this );
  322.     else
  323.       throw;
  324.   }
  325. }
  326.  
  327.  
  328. void __fastcall TIBEventAlerter::Notification(Classes::TComponent *AComponent, Classes::TOperation Operation )
  329. {
  330.   TIBComponent::Notification( AComponent, Operation);
  331.   if( Operation == opRemove && AComponent == Database)// then
  332.   {
  333.     UnRegisterEvents();
  334.     Database = NULL;
  335.   }
  336. }
  337.  
  338.  
  339.  
  340. void __fastcall TIBEventAlerter::QueueEvents(void)
  341. {
  342.   if( !FRegistered ) //then
  343.     throw EIBError( SNoEventsRegistered);
  344.   if( ProcessingEvents ) //then
  345.     throw EIBError( SInvalidQueueing);
  346.   if( !FQueued ) //then
  347.   {
  348.     try
  349.       // wait until current event handler is finished before queuing events
  350.     {
  351.       EnterCriticalSection( &CS);
  352.       DoQueueEvents();
  353.       Changing = true;
  354.       LeaveCriticalSection( &CS);
  355.     }
  356.     catch(...)
  357.     {
  358.       LeaveCriticalSection( &CS);
  359.       throw;
  360.     }
  361.   }
  362. }
  363.  
  364.  
  365.  
  366. void __fastcall TIBEventAlerter::RegisterEvents(void)
  367. {
  368.   ValidateDatabase( Database);
  369.   if( ComponentState.Contains( csDesigning )  )
  370.     FRegistered = true;
  371.   else
  372.   {
  373.     UnRegisterEvents();
  374.     if( Events->Count == 0 )
  375.        return;
  376.     for(int i = 0; i < Events->Count; i++ )
  377.       strcpy( Buffer[i], Events->Strings[i].c_str());
  378.  
  379.     EventBufferLen = IscEventBlock(EventBuffer,
  380.                                    ResultBuffer,
  381.                                    Events->Count,
  382.                                    Buffer[0]);
  383.     /*
  384.     asm
  385.     {
  386.       mov ecx, dword ptr [i]
  387.       mov eax, dword ptr [bufptr]
  388.       @@1:
  389.       push eax
  390.       add  eax, EventLength
  391.       loop @@1
  392.       push dword ptr [i]
  393.       push dword ptr [resultBufPtr]
  394.       push dword ptr [eventBufPtr]
  395.       call [IscEventBlock]
  396.       mov  dword ptr [buflen], eax
  397.       mov eax, dword ptr [i]
  398.       shl eax, 2
  399.       add eax, 12
  400.       add esp, eax
  401.      }*/ // end asm block
  402.     FRegistered = true;
  403.     QueueEvents();
  404.   }
  405. }
  406.  
  407.  
  408.  
  409.  
  410.  
  411. void __fastcall TIBEventAlerter::SetEvents(Classes::TStrings *value)
  412. {
  413.   FEvents->Assign( value);
  414. }
  415.  
  416.  
  417. void __fastcall TIBEventAlerter::SetDatabase(Db::TDatabase *value)
  418. {
  419.   if( value != Database )
  420.   {
  421.     UnRegisterEvents();
  422.     if( value != NULL  && value->Connected ) //!!assigned?
  423.        ValidateDatabase( value);
  424.     Database = value;
  425.   }
  426. }
  427.  
  428.  
  429.  
  430. void __fastcall TIBEventAlerter::SetRegistered( bool value )
  431. {
  432.   if( ComponentState.Contains ( csReading  ) )
  433.     RegisteredState = value;
  434.   else
  435.     if( FRegistered != value )
  436.       if( value )
  437.         RegisterEvents();
  438.       else
  439.         UnRegisterEvents();
  440. }
  441.  
  442.  
  443.  
  444. void __fastcall TIBEventAlerter::UnRegisterEvents(void)
  445. {
  446.   if( ProcessingEvents )
  447.      throw EIBError( SInvalidRegistration);
  448.   if( ComponentState.Contains( csDesigning  ) )
  449.     FRegistered = false;
  450.   else
  451.    if( ComponentState.Contains( csLoading  ) != true )
  452.    {
  453.     CancelEvents();
  454.     if( FRegistered )
  455.     {
  456.       IscFree( EventBuffer);
  457.       EventBuffer = NULL;
  458.       IscFree( ResultBuffer);
  459.       ResultBuffer = NULL;
  460.     }
  461.     FRegistered = false;
  462.    }
  463. }
  464.  
  465.  
  466.  
  467.  
  468. void __fastcall TIBEventAlerter::UpdateResultBuffer(int length, System::PChar updated)
  469. {
  470.   int i;
  471.   for( i = 0; i<  length; i++  )
  472.     ResultBuffer[i] = updated[i];
  473. }
  474.  
  475.  
  476.  
  477.