source: cprs/trunk/CPRS-Lib/ORNet.pas@ 1710

Last change on this file since 1710 was 1679, checked in by healthsevak, 9 years ago

Updating the working copy to CPRS version 28

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