ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/IBEvents.pas
Revision: 1
Committed: Mon Jul 31 16:43:00 2000 UTC (23 years, 8 months ago) by tony
Content type: text/x-pascal
File size: 10947 byte(s)
Log Message:
Borland IBX Open Source Release

File Contents

# Content
1 {************************************************************************}
2 { }
3 { Borland Delphi Visual Component Library }
4 { InterBase Express core components }
5 { }
6 { Copyright (c) 1998-2000 Inprise Corporation }
7 { }
8 { InterBase Express is based in part on the product }
9 { Free IB Components, written by Gregory H. Deatz for }
10 { Hoagland, Longo, Moran, Dunst & Doukas Company. }
11 { Free IB Components is used under license. }
12 { }
13 { The contents of this file are subject to the InterBase }
14 { Public License Version 1.0 (the "License"); you may not }
15 { use this file except in compliance with the License. You }
16 { may obtain a copy of the License at http://www.Inprise.com/IPL.html }
17 { Software distributed under the License is distributed on }
18 { an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either }
19 { express or implied. See the License for the specific language }
20 { governing rights and limitations under the License. }
21 { The Original Code was created by InterBase Software Corporation }
22 { and its successors. }
23 { Portions created by Inprise Corporation are Copyright (C) Inprise }
24 { Corporation. All Rights Reserved. }
25 { Contributor(s): Jeff Overcash }
26 { }
27 {************************************************************************}
28
29 unit IBEvents;
30
31 interface
32
33 uses
34 SysUtils, Windows, Messages, Classes, Graphics, Controls,
35 Forms, Dialogs, DB, IBHeader, IBExternals, IB, IBDatabase;
36
37 const
38 MaxEvents = 15;
39 EventLength = 64;
40
41 type
42
43 TEventAlert = procedure( Sender: TObject; EventName: string; EventCount: longint;
44 var CancelAlerts: Boolean) of object;
45
46 TEventBuffer = array[ 0..MaxEvents-1, 0..EventLength-1] of char;
47
48 TIBEvents = class(TComponent)
49 private
50 FIBLoaded: Boolean;
51 FEvents: TStrings;
52 FOnEventAlert: TEventAlert;
53 FQueued: Boolean;
54 FRegistered: Boolean;
55 Buffer: TEventBuffer;
56 Changing: Boolean;
57 CS: TRTLCriticalSection;
58 EventBuffer: PChar;
59 EventBufferLen: integer;
60 EventID: ISC_LONG;
61 ProcessingEvents: Boolean;
62 RegisteredState: Boolean;
63 ResultBuffer: PChar;
64 FDatabase: TIBDatabase;
65 procedure SetDatabase( value: TIBDatabase);
66 procedure ValidateDatabase( Database: TIBDatabase);
67 procedure DoQueueEvents;
68 procedure EventChange( sender: TObject);
69 procedure UpdateResultBuffer( length: short; updated: PChar);
70 protected
71 procedure HandleEvent;
72 procedure Loaded; override;
73 procedure Notification( AComponent: TComponent; Operation: TOperation); override;
74 procedure SetEvents( value: TStrings);
75 procedure SetRegistered( value: boolean);
76 function GetNativeHandle: TISC_DB_HANDLE;
77
78 public
79 constructor Create( AOwner: TComponent); override;
80 destructor Destroy; override;
81 procedure CancelEvents;
82 procedure QueueEvents;
83 procedure RegisterEvents;
84 procedure UnRegisterEvents;
85 property Queued: Boolean read FQueued;
86 published
87 property Database: TIBDatabase read FDatabase write SetDatabase;
88 property Events: TStrings read FEvents write SetEvents;
89 property Registered: Boolean read FRegistered write SetRegistered;
90 property OnEventAlert: TEventAlert read FOnEventAlert write FOnEventAlert;
91 end;
92
93 implementation
94
95 uses
96 IBIntf;
97
98 function TIBEvents.GetNativeHandle: TISC_DB_HANDLE;
99 begin
100 if assigned( FDatabase) and FDatabase.Connected then
101 Result := FDatabase.Handle
102 else result := nil;
103 end;
104
105 procedure TIBEvents.ValidateDatabase( Database: TIBDatabase);
106 begin
107 if not assigned( Database) then
108 IBError(ibxeDatabaseNameMissing, [nil]);
109 if not Database.Connected then
110 IBError(ibxeDatabaseClosed, [nil]);
111 end;
112
113 { TIBEvents }
114
115 procedure HandleEvent( param: integer); stdcall;
116 begin
117 { don't let exceptions propogate out of thread }
118 try
119 TIBEvents( param).HandleEvent;
120 except
121 Application.HandleException( nil);
122 end;
123 end;
124
125 procedure IBEventCallback( ptr: pointer; length: short; updated: PChar); cdecl;
126 var
127 ThreadID: DWORD;
128 begin
129 { Handle events asynchronously in second thread }
130 EnterCriticalSection( TIBEvents( ptr).CS);
131 TIBEvents( ptr).UpdateResultBuffer( length, updated);
132 if TIBEvents( ptr).Queued then
133 CloseHandle( CreateThread( nil, 8192, @HandleEvent, ptr, 0, ThreadID));
134 LeaveCriticalSection( TIBEvents( ptr).CS);
135 end;
136
137 constructor TIBEvents.Create( AOwner: TComponent);
138 begin
139 inherited Create( AOwner);
140 FIBLoaded := False;
141 CheckIBLoaded;
142 FIBLoaded := True;
143 InitializeCriticalSection( CS);
144 FEvents := TStringList.Create;
145 with TStringList( FEvents) do
146 begin
147 OnChange := EventChange;
148 Duplicates := dupIgnore;
149 end;
150 end;
151
152 destructor TIBEvents.Destroy;
153 begin
154 if FIBLoaded then
155 begin
156 UnregisterEvents;
157 SetDatabase( nil);
158 TStringList(FEvents).OnChange := nil;
159 FEvents.Free;
160 DeleteCriticalSection( CS);
161 end;
162 inherited Destroy;
163 end;
164
165 procedure TIBEvents.CancelEvents;
166 begin
167 if ProcessingEvents then
168 IBError(ibxeInvalidCancellation, [nil]);
169 if FQueued then
170 begin
171 try
172 { wait for event handler to finish before cancelling events }
173 EnterCriticalSection( CS);
174 ValidateDatabase( Database);
175 FQueued := false;
176 Changing := true;
177 if (isc_Cancel_events( StatusVector, @FDatabase.Handle, @EventID) > 0) then
178 IBDatabaseError;
179 finally
180 LeaveCriticalSection( CS);
181 end;
182 end;
183 end;
184
185 procedure TIBEvents.DoQueueEvents;
186 var
187 callback: pointer;
188 begin
189 ValidateDatabase( DataBase);
190 callback := @IBEventCallback;
191 if (isc_que_events( StatusVector, @FDatabase.Handle, @EventID, EventBufferLen,
192 EventBuffer, TISC_CALLBACK(callback), PVoid(Self)) > 0) then
193 IBDatabaseError;
194 FQueued := true;
195 end;
196
197 procedure TIBEvents.EventChange( sender: TObject);
198 begin
199 { check for blank event }
200 if TStringList(Events).IndexOf( '') <> -1 then
201 IBError(ibxeInvalidEvent, [nil]);
202 { check for too many events }
203 if Events.Count > MaxEvents then
204 begin
205 TStringList(Events).OnChange := nil;
206 Events.Delete( MaxEvents);
207 TStringList(Events).OnChange := EventChange;
208 IBError(ibxeMaximumEvents, [nil]);
209 end;
210 if Registered then RegisterEvents;
211 end;
212
213 procedure TIBEvents.HandleEvent;
214 var
215 Status: PStatusVector;
216 CancelAlerts: Boolean;
217 i: integer;
218 begin
219 try
220 { prevent modification of vital data structures while handling events }
221 EnterCriticalSection( CS);
222 ProcessingEvents := true;
223 isc_event_counts( StatusVector, EventBufferLen, EventBuffer, ResultBuffer);
224 CancelAlerts := false;
225 if assigned(FOnEventAlert) and not Changing then
226 begin
227 for i := 0 to Events.Count-1 do
228 begin
229 try
230 Status := StatusVectorArray;
231 if (Status[i] <> 0) and not CancelAlerts then
232 FOnEventAlert( self, Events[Events.Count-i-1], Status[i], CancelAlerts);
233 except
234 Application.HandleException( nil);
235 end;
236 end;
237 end;
238 Changing := false;
239 if not CancelAlerts and FQueued then DoQueueEvents;
240 finally
241 ProcessingEvents := false;
242 LeaveCriticalSection( CS);
243 end;
244 end;
245
246 procedure TIBEvents.Loaded;
247 begin
248 inherited Loaded;
249 try
250 if RegisteredState then RegisterEvents;
251 except
252 if csDesigning in ComponentState then
253 Application.HandleException( self)
254 else raise;
255 end;
256 end;
257
258 procedure TIBEvents.Notification( AComponent: TComponent;
259 Operation: TOperation);
260 begin
261 inherited Notification( AComponent, Operation);
262 if (Operation = opRemove) and (AComponent = FDatabase) then
263 begin
264 UnregisterEvents;
265 FDatabase := nil;
266 end;
267 end;
268
269 procedure TIBEvents.QueueEvents;
270 begin
271 if not FRegistered then
272 IBError(ibxeNoEventsRegistered, [nil]);
273 if ProcessingEvents then
274 IBError(ibxeInvalidQueueing, [nil]);
275 if not FQueued then
276 begin
277 try
278 { wait until current event handler is finished before queuing events }
279 EnterCriticalSection( CS);
280 DoQueueEvents;
281 Changing := true;
282 finally
283 LeaveCriticalSection( CS);
284 end;
285 end;
286 end;
287
288 procedure TIBEvents.RegisterEvents;
289 var
290 i: integer;
291 bufptr: pointer;
292 eventbufptr: pointer;
293 resultbufptr: pointer;
294 buflen: integer;
295 begin
296 ValidateDatabase( Database);
297 if csDesigning in ComponentState then FRegistered := true
298 else begin
299 UnregisterEvents;
300 if Events.Count = 0 then exit;
301 for i := 0 to Events.Count-1 do
302 StrPCopy( @Buffer[i][0], Events[i]);
303 i := Events.Count;
304 bufptr := @buffer[0];
305 eventbufptr := @EventBuffer;
306 resultBufPtr := @ResultBuffer;
307 asm
308 mov ecx, dword ptr [i]
309 mov eax, dword ptr [bufptr]
310 @@1:
311 push eax
312 add eax, EventLength
313 loop @@1
314 push dword ptr [i]
315 push dword ptr [resultBufPtr]
316 push dword ptr [eventBufPtr]
317 call [isc_event_block]
318 mov dword ptr [bufLen], eax
319 mov eax, dword ptr [i]
320 shl eax, 2
321 add eax, 12
322 add esp, eax
323 end;
324 EventBufferlen := Buflen;
325 FRegistered := true;
326 QueueEvents;
327 end;
328 end;
329
330 procedure TIBEvents.SetEvents( value: TStrings);
331 begin
332 FEvents.Assign( value);
333 end;
334
335 procedure TIBEvents.SetDatabase( value: TIBDatabase);
336 begin
337 if value <> FDatabase then
338 begin
339 UnregisterEvents;
340 if assigned( value) and value.Connected then ValidateDatabase( value);
341 FDatabase := value;
342 end;
343 end;
344
345 procedure TIBEvents.SetRegistered( value: Boolean);
346 begin
347 if (csReading in ComponentState) then
348 RegisteredState := value
349 else if FRegistered <> value then
350 if value then RegisterEvents else UnregisterEvents;
351 end;
352
353 procedure TIBEvents.UnregisterEvents;
354 begin
355 if ProcessingEvents then
356 IBError(ibxeInvalidRegistration, [nil]);
357 if csDesigning in ComponentState then
358 FRegistered := false
359 else if not (csLoading in ComponentState) then
360 begin
361 CancelEvents;
362 if FRegistered then
363 begin
364 isc_free( EventBuffer);
365 EventBuffer := nil;
366 isc_free( ResultBuffer);
367 ResultBuffer := nil;
368 end;
369 FRegistered := false;
370 end;
371 end;
372
373 procedure TIBEvents.UpdateResultBuffer( length: short; updated: PChar);
374 var
375 i: integer;
376 begin
377 for i := 0 to length-1 do
378 ResultBuffer[i] := updated[i];
379 end;
380
381 end.