source: cprs/branches/tmg-cprs/CPRS-Lib/ORNet.pas@ 770

Last change on this file since 770 was 738, checked in by Kevin Toppenberg, 15 years ago

Fixed Text Object Parameters

File size: 17.4 KB
RevLine 
[453]1unit ORNet;
2
3{$DEFINE CCOWBROKER}
4
5interface
6
[654]7uses SysUtils, Windows, Classes, Forms, Controls, ORFn, TRPCB, RPCConf1, Dialogs
[453]8{$IFDEF CCOWBROKER}, CCOWRPCBroker {$ENDIF} ; //, SharedRPCBroker;
9
10
11procedure SetBrokerServer(const AName: string; APort: Integer; WantDebug: Boolean);
12function AuthorizedOption(const OptionName: string): Boolean;
13function ConnectToServer(const OptionName: string): Boolean;
14function MRef(glvn: string): string;
15procedure CallV(const RPCName: string; const AParam: array of const);
16function sCallV(const RPCName: string; const AParam: array of const): string;
17procedure tCallV(ReturnData: TStrings; const RPCName: string; const AParam: array of const);
18function UpdateContext(NewContext: string): boolean;
19function IsBaseContext: boolean;
20procedure CallBrokerInContext;
21procedure CallBroker;
22function RetainedRPCCount: Integer;
23procedure SetRetainedRPCMax(Value: Integer);
24function GetRPCMax: integer;
25procedure LoadRPCData(Dest: TStrings; ID: Integer);
[738]26function AccessRPCData(ID: Integer) : TStringList; //kt added -- Caller DOESN'T own object
[453]27function DottedIPStr: string;
28procedure CallRPCWhenIdle(CallProc: TORIdleCallProc; Msg: String);
29procedure EnsureBroker;
[612]30procedure RPCCallsClear; //kt added
[453]31
32(*
33function pCallV(const RPCName: string; const AParam: array of const): PChar;
34procedure wCallV(AControl: TControl; const RPCName: string; const AParam: array of const);
35procedure WrapWP(Buf: pChar);
36*)
37
38var
39{$IFDEF CCOWBROKER}
40 RPCBrokerV: TCCOWRPCBroker;
41{$ELSE}
42 RPCBrokerV: TRPCBroker;
43 //RPCBrokerV: TSharedRPCBroker;
44{$ENDIF}
45 RPCLastCall: string;
46
47implementation
48
[612]49uses
50 DateUtils, //kt
51 Winsock;
[453]52
53const
54 // *** these are constants from RPCBErr.pas, will broker document them????
55 XWB_M_REJECT = 20000 + 2; // M error
56 XWB_BadSignOn = 20000 + 4; // SignOn 'Error' (happens when cancel pressed)
57
58var
59 uCallList: TList;
60 uMaxCalls: Integer;
61 uShowRPCs: Boolean;
62 uBaseContext: string = '';
63 uCurrentContext: string = '';
64
65{ private procedures and functions ---------------------------------------------------------- }
66
67procedure EnsureBroker;
68{ ensures that a broker object has been created - creates & initializes it if necessary }
69begin
70 if RPCBrokerV = nil then
71 begin
72{$IFDEF CCOWBROKER}
73 RPCBrokerV := TCCOWRPCBroker.Create(Application);
74{$ELSE}
75 RPCBrokerV := TRPCBroker.Create(Application);
76 //RPCBrokerV := TSharedRPCBroker.Create(Application);
77{$ENDIF}
78 with RPCBrokerV do
79 begin
80 KernelLogIn := True;
81 Login.Mode := lmAppHandle;
82 ClearParameters := True;
83 ClearResults := True;
84 DebugMode := False;
85 end;
86 end;
87end;
88
89procedure SetList(AStringList: TStrings; ParamIndex: Integer);
90{ places TStrings into RPCBrokerV.Mult[n], where n is a 1-based (not 0-based) index }
91var
92 i: Integer;
93begin
94 with RPCBrokerV.Param[ParamIndex] do
95 begin
96 PType := list;
97 with AStringList do for i := 0 to Count - 1 do Mult[IntToStr(i+1)] := Strings[i];
98 end;
99end;
100
101procedure SetParams(const RPCName: string; const AParam: array of const);
102{ takes the params (array of const) passed to xCallV and sets them into RPCBrokerV.Param[i] }
103const
104 BoolChar: array[boolean] of char = ('0', '1');
105var
106 i: integer;
107 TmpExt: Extended;
108begin
109 RPCLastCall := RPCName + ' (SetParam begin)';
110 if Length(RPCName) = 0 then raise Exception.Create('No RPC Name');
111 EnsureBroker;
112 with RPCBrokerV do
113 begin
114 ClearParameters := True;
115 RemoteProcedure := RPCName;
116 for i := 0 to High(AParam) do with AParam[i] do
117 begin
118 Param[i].PType := literal;
119 case VType of
120 vtInteger: Param[i].Value := IntToStr(VInteger);
121 vtBoolean: Param[i].Value := BoolChar[VBoolean];
122 vtChar: if VChar = #0 then
123 Param[i].Value := ''
124 else
125 Param[i].Value := VChar;
126 //vtExtended: Param[i].Value := FloatToStr(VExtended^);
127 vtExtended: begin
128 TmpExt := VExtended^;
129 if(abs(TmpExt) < 0.0000000000001) then TmpExt := 0;
130 Param[i].Value := FloatToStr(TmpExt);
131 end;
132 vtString: with Param[i] do
133 begin
134 Value := VString^;
135 if (Length(Value) > 0) and (Value[1] = #1) then
136 begin
137 Value := Copy(Value, 2, Length(Value));
138 PType := reference;
139 end;
140 end;
141 vtPChar: Param[i].Value := StrPas(VPChar);
142 vtPointer: if VPointer = nil
143 then ClearParameters := True {Param[i].PType := null}
144 else raise Exception.Create('Pointer type must be nil.');
145 vtObject: if VObject is TStrings then SetList(TStrings(VObject), i);
146 vtAnsiString: with Param[i] do
147 begin
148 Value := string(VAnsiString);
149 if (Length(Value) > 0) and (Value[1] = #1) then
150 begin
151 Value := Copy(Value, 2, Length(Value));
152 PType := reference;
153 end;
154 end;
155 vtInt64: Param[i].Value := IntToStr(VInt64^);
156 else raise Exception.Create('Unable to pass parameter type to Broker.');
157 end; {case}
158 end; {for}
159 end; {with}
160 RPCLastCall := RPCName + ' (SetParam end)';
161end;
162
163{ public procedures and functions ----------------------------------------------------------- }
164
165function UpdateContext(NewContext: string): boolean;
166begin
167 if NewContext = uCurrentContext then
168 Result := TRUE
169 else
170 begin
171 Result := RPCBrokerV.CreateContext(NewContext);
172 if Result then
173 uCurrentContext := NewContext
174 else
175 if (NewContext <> uBaseContext) and RPCBrokerV.CreateContext(uBaseContext) then
176 uCurrentContext := uBaseContext
177 else
178 uCurrentContext := '';
179 end;
180end;
181
182function IsBaseContext: boolean;
183begin
184 Result := ((uCurrentContext = uBaseContext) or (uCurrentContext = ''));
185end;
186
187procedure CallBrokerInContext;
188var
189 AStringList: TStringList;
190 i, j: Integer;
191 x, y: string;
[612]192 Time1,Time2 : TDateTime; //kt
[453]193begin
194 RPCLastCall := RPCBrokerV.RemoteProcedure + ' (CallBroker begin)';
195 if uShowRPCs then StatusText(RPCBrokerV.RemoteProcedure);
196 with RPCBrokerV do if not Connected then // happens if broker connection is lost
197 begin
198 ClearResults := True;
199 Exit;
200 end;
201 if uCallList.Count = uMaxCalls then
202 begin
203 AStringList := uCallList.Items[0];
204 AStringList.Free;
205 uCallList.Delete(0);
206 end;
207 AStringList := TStringList.Create;
208 AStringList.Add(RPCBrokerV.RemoteProcedure);
209 if uCurrentContext <> uBaseContext then
210 AStringList.Add('Context: ' + uCurrentContext);
[612]211 Time1 := GetTime; //kt
212 AStringList.Add('Called at: '+ TimeToStr(Time1)); //kt
[453]213 AStringList.Add(' ');
214 AStringList.Add('Params ------------------------------------------------------------------');
215 with RPCBrokerV do for i := 0 to Param.Count - 1 do
216 begin
217 case Param[i].PType of
218 //global: x := 'global';
219 list: x := 'list';
220 literal: x := 'literal';
221 //null: x := 'null';
222 reference: x := 'reference';
223 undefined: x := 'undefined';
224 //wordproc: x := 'wordproc';
225 end;
226 AStringList.Add(x + #9 + Param[i].Value);
227 if Param[i].PType = list then
228 begin
229 for j := 0 to Param[i].Mult.Count - 1 do
230 begin
231 x := Param[i].Mult.Subscript(j);
232 y := Param[i].Mult[x];
233 AStringList.Add(#9 + '(' + x + ')=' + y);
234 end;
235 end;
236 end; {with...for}
237 //RPCBrokerV.Call;
238 try
239 RPCBrokerV.Call;
240 except
241 // The broker erroneously sets connected to false if there is any error (including an
242 // error on the M side). It should only set connection to false if there is no connection.
243 on E:EBrokerError do
244 begin
245 if E.Code = XWB_M_REJECT then
246 begin
247 x := 'An error occurred on the server.' + CRLF + CRLF + E.Action;
248 Application.MessageBox(PChar(x), 'Server Error', MB_OK);
249 end
250 else raise;
251 (*
252 case E.Code of
253 XWB_M_REJECT: begin
254 x := 'An error occurred on the server.' + CRLF + CRLF + E.Action;
255 Application.MessageBox(PChar(x), 'Server Error', MB_OK);
256 end;
257 else begin
258 x := 'An error occurred with the network connection.' + CRLF +
259 'Action was: ' + E.Action + CRLF + 'Code was: ' + E.Mnemonic +
260 CRLF + CRLF + 'Application cannot continue.';
261 Application.MessageBox(PChar(x), 'Network Error', MB_OK);
262 end;
263 end;
264 *)
265 // make optional later...
266 if not RPCBrokerV.Connected then Application.Terminate;
267 end;
268 end;
269 AStringList.Add(' ');
270 AStringList.Add('Results -----------------------------------------------------------------');
271 AStringList.AddStrings(RPCBrokerV.Results);
[612]272 AStringList.Add(' '); //kt
273 Time2 := GetTime; //kt
274 AStringList.Add('Elapsed Time: ' + IntToStr(Round(MilliSecondSpan(Time2,Time1))) + ' ms'); //kt
[453]275 uCallList.Add(AStringList);
276 if uShowRPCs then StatusText('');
277 RPCLastCall := RPCBrokerV.RemoteProcedure + ' (completed)';
278end;
279
280procedure CallBroker;
281begin
282 UpdateContext(uBaseContext);
283 CallBrokerInContext;
284end;
285
286procedure SetBrokerServer(const AName: string; APort: Integer; WantDebug: Boolean);
287{ makes the initial connection to a server }
288begin
289 EnsureBroker;
290 with RPCBrokerV do
291 begin
292 Server := AName;
293 if APort > 0 then ListenerPort := APort;
294 DebugMode := WantDebug;
295 Connected := True;
296 end;
297end;
298
299function AuthorizedOption(const OptionName: string): Boolean;
300{ checks to see if the user is authorized to use this application }
301begin
302 EnsureBroker;
303 Result := RPCBrokerV.CreateContext(OptionName);
304 if Result then
305 begin
306 if (uBaseContext = '') then
307 uBaseContext := OptionName;
308 uCurrentContext := OptionName;
309 end;
310end;
311
312function ConnectToServer(const OptionName: string): Boolean;
313{ establish initial connection to server using optional command line parameters and check that
314 this application (option) is allowed for this user }
315var
316 WantDebug: Boolean;
317 AServer, APort, x: string;
318 i, ModalResult: Integer;
319begin
320 Result := False;
321 WantDebug := False;
322 AServer := '';
323 APort := '';
324 for i := 1 to ParamCount do // params may be: S[ERVER]=hostname P[ORT]=port DEBUG
325 begin
326 if UpperCase(ParamStr(i)) = 'DEBUG' then WantDebug := True;
327 if UpperCase(ParamStr(i)) = 'SHOWRPCS' then uShowRPCs := True;
328 x := UpperCase(Piece(ParamStr(i), '=', 1));
329 if (x = 'S') or (x = 'SERVER') then AServer := Piece(ParamStr(i), '=', 2);
330 if (x = 'P') or (x = 'PORT') then APort := Piece(ParamStr(i), '=', 2);
331 end;
332 if (AServer = '') or (APort = '') then
333 begin
334 ModalResult := GetServerInfo(AServer, APort);
335 if ModalResult = mrCancel then Exit;
336 end;
337 // use try..except to work around errors in the Broker SignOn screen
338 try
339 SetBrokerServer(AServer, StrToIntDef(APort, 9200), WantDebug);
340 Result := AuthorizedOption(OptionName);
341 if Result then Result := RPCBrokerV.Connected;
342 RPCBrokerV.RPCTimeLimit := 300;
343 except
344 on E:EBrokerError do
345 begin
346 if E.Code <> XWB_BadSignOn then InfoBox(E.Message, 'Error', MB_OK or MB_ICONERROR);
347 Result := False;
348 end;
349 end;
350end;
351
352function MRef(glvn: string): string;
353{ prepends ASCII 1 to string, allows SetParams to interpret as an M reference }
354begin
355 Result := #1 + glvn;
356end;
357
358procedure CallV(const RPCName: string; const AParam: array of const);
359{ calls the broker leaving results in results property which must be read by caller }
360var
361 SavedCursor: TCursor;
362begin
363 SavedCursor := Screen.Cursor;
364 Screen.Cursor := crHourGlass;
365 SetParams(RPCName, AParam);
366 CallBroker; //RPCBrokerV.Call;
367 Screen.Cursor := SavedCursor;
368end;
369
370function sCallV(const RPCName: string; const AParam: array of const): string;
371{ calls the broker and returns a scalar value. }
372var
373 SavedCursor: TCursor;
374begin
375 SavedCursor := Screen.Cursor;
376 Screen.Cursor := crHourGlass;
377 SetParams(RPCName, AParam);
378 CallBroker; //RPCBrokerV.Call;
379 if RPCBrokerV.Results.Count > 0 then Result := RPCBrokerV.Results[0] else Result := '';
380 Screen.Cursor := SavedCursor;
381end;
382
383procedure tCallV(ReturnData: TStrings; const RPCName: string; const AParam: array of const);
384{ calls the broker and returns TStrings data }
385var
386 SavedCursor: TCursor;
387begin
388 if ReturnData = nil then raise Exception.Create('TString not created');
389 SavedCursor := Screen.Cursor;
390 Screen.Cursor := crHourGlass;
391 SetParams(RPCName, AParam);
392 CallBroker; //RPCBrokerV.Call;
393 ReturnData.Assign(RPCBrokerV.Results);
394 Screen.Cursor := SavedCursor;
395end;
396
397(* uncomment if these are needed -
398
399function pCallV(const RPCName: string; const AParam: array of const): PChar;
400{ Calls the Broker. Result is a PChar containing raw Broker data. }
401{ -- Caller must dispose the string that is returned -- }
402var
403 SavedCursor: TCursor;
404begin
405 SavedCursor := Screen.Cursor;
406 Screen.Cursor := crHourGlass;
407 SetParams(RPCName, AParam);
408 RPCBrokerV.Call;
409 pCallV := StrNew(RPCBrokerV.Results.GetText);
410 Screen.Cursor := SavedCursor;
411end;
412
413procedure wCallV(AControl: TControl; const RPCName: string; const AParam: array of const);
414{ Calls the Broker. Places data into control (wrapped). }
415var
416 BufPtr: PChar;
417begin
418 BufPtr := pCallV(RPCName, AParam);
419 WrapWP(BufPtr);
420 AControl.SetTextBuf(BufPtr);
421 StrDispose(BufPtr);
422end;
423
424procedure WrapWP(Buf: pChar);
425{ Iterates through Buf and wraps text in the same way that FM wraps text. }
426var
427 PSub: PChar;
428begin
429 PSub := StrScan(Buf, #13);
430 while PSub <> nil do
431 begin
432 if Ord(PSub[2]) > 32 then
433 begin
434 StrMove(PSub, PSub + SizeOf(Char), StrLen(PSub));
435 PSub[0] := #32;
436 end
437 else repeat Inc(PSub, SizeOf(Char)) until (Ord(PSub[0]) > 32) or (PSub = StrEnd(PSub));
438 PSub := StrScan(PSub, #13);
439 end;
440end;
441
442*)
443
444function RetainedRPCCount: Integer;
445begin
446 Result := uCallList.Count;
447end;
448
449procedure SetRetainedRPCMax(Value: Integer);
450begin
451 if Value > 0 then uMaxCalls := Value;
452end;
453
454function GetRPCMax: integer;
455begin
456 Result := uMaxCalls;
457end;
458
459procedure LoadRPCData(Dest: TStrings; ID: Integer);
460begin
461 if (ID > -1) and (ID < uCallList.Count) then Dest.Assign(TStringList(uCallList.Items[ID]));
462end;
463
[738]464function AccessRPCData(ID: Integer) : TStringList;
465//kt added -- Caller DOESN'T own object
466begin
467 Result := nil;
468 if (ID > -1) and (ID < uCallList.Count) then Result := TStringList(uCallList.Items[ID]);
469end;
470
471
[453]472function DottedIPStr: string;
473{ return the IP address of the local machine as a string in dotted form: nnn.nnn.nnn.nnn }
474const
475 WINSOCK1_1 = $0101; // minimum required version of WinSock
476 SUCCESS = 0; // value returned by WinSock functions if no error
477var
478 //WSAData: TWSAData; // structure to hold startup information
479 HostEnt: PHostEnt; // pointer to Host Info structure (see WinSock 1.1, page 60)
480 IPAddr: PInAddr; // pointer to IP address in network order (4 bytes)
481 LocalName: array[0..255] of Char; // buffer for the name of the client machine
482begin
483 Result := 'No IP Address';
484 // ensure the Winsock DLL has been loaded (should be if there is a broker connection)
485 //if WSAStartup(WINSOCK1_1, WSAData) <> SUCCESS then Exit;
486 //try
487 // get the name of the client machine
488 if gethostname(LocalName, SizeOf(LocalName) - 1) <> SUCCESS then Exit;
489 // get information about the client machine (contained in a record of type THostEnt)
490 HostEnt := gethostbyname(LocalName);
491 if HostEnt = nil then Exit;
492 // get a pointer to the four bytes that contain the IP address
493 // Dereference HostEnt to get the THostEnt record. In turn, dereference the h_addr_list
494 // field to get a pointer to the IP address. The pointer to the IP address is type PChar,
495 // so it needs to be typecast as PInAddr in order to make the call to inet_ntoa.
496 IPAddr := PInAddr(HostEnt^.h_addr_list^);
497 // Dereference IPAddr (which is a PChar typecast as PInAddr) to get the 4 bytes that need
498 // to be passed to inet_ntoa. A string with the IP address in dotted format is returned.
499 Result := inet_ntoa(IPAddr^);
500 //finally
501 // causes the reference counter in Winsock (set by WSAStartup, above) to be decremented
502 //WSACleanup;
503 //end;
504end;
505
506procedure RPCIdleCallDone(Msg: string);
507begin
508 RPCBrokerV.ClearResults := True;
509end;
510
511procedure CallRPCWhenIdle(CallProc: TORIdleCallProc; Msg: String);
512begin
513 CallWhenIdleNotifyWhenDone(CallProc, RPCIdleCallDone, Msg);
514end;
515
[612]516procedure RPCCallsClear;
517//kt Added entire fuction.
518begin
519 while uCallList.Count > 0 do
520 begin
521 TStringList(uCallList.Items[0]).Free;
522 uCallList.Delete(0);
523 end;
524end;
525
[453]526initialization
527 RPCBrokerV := nil;
528 RPCLastCall := 'No RPCs called';
529 uCallList := TList.Create;
[612]530 uMaxCalls := 150; //kt 10
[453]531 uShowRPCs := False;
532
533finalization
[612]534 { //kt commented out
[453]535 while uCallList.Count > 0 do
536 begin
537 TStringList(uCallList.Items[0]).Free;
538 uCallList.Delete(0);
539 end;
[612]540 }
541 RPCCallsClear; //kt added
[453]542 uCallList.Free;
543
544end.
Note: See TracBrowser for help on using the repository browser.