Difference between revisions of "Broker help"

From VistApedia
Jump to: navigation, search
(Added a glossary link to Configuration~)
 
(6 intermediate revisions by the same user not shown)
Line 238: Line 238:
  
  
See the "Historical Information Regarding the 16-Bit BDK vs. 32-Bit BDK" topic for properties and methods introduced with the RPC Broker 32-bit BDK. This topic also highlights disposition of the Client Manager and those properties and parameters that were obsolete and removed from the 32-bit version of the BDK.
+
See the "[[Historical~|Historical]] Information Regarding the 16-Bit BDK vs. 32-Bit BDK" topic for properties and methods introduced with the RPC Broker 32-bit BDK. This topic also highlights disposition of the Client Manager and those properties and parameters that were obsolete and removed from the 32-bit version of the BDK.
  
  
Line 359: Line 359:
 
Connect
 
Connect
  
The first time one of the Broker components in your application connects, it will establish an actual connection with the server. The connection record will be added to the list of all active connections for your application. This list is internal to the application and is completely under the control of the Broker component and is transparent to you. If another Broker component tries to connect to the same server/port, the existing connection record will be found in the list and its socket will be shared. The new connection will also be added to this list. This process is repeated with each connection request.
+
The first time one of the Broker components in your application connects, it will establish an actual connection with the server. The connection [[record~|Record]] will be added to the list of all active connections for your application. This list is internal to the application and is completely under the control of the Broker component and is transparent to you. If another Broker component tries to connect to the same server/port, the existing connection [[record~|Record]] will be found in the list and its socket will be shared. The new connection will also be added to this list. This process is repeated with each connection request.
  
  
 
Disconnect
 
Disconnect
  
When a Broker component disconnects, its connection record is removed from the internal list of active connections. If it happens to be the last record for the particular server/port combination, the connection is actually closed. This scheme provides the illusion of multiple connections without "clogging up" the server.
+
When a Broker component disconnects, its connection [[record~|Record]] is removed from the internal list of active connections. If it happens to be the last record for the particular server/port combination, the connection is actually closed. This scheme provides the illusion of multiple connections without "clogging up" the server.
  
 
Context-sensitive Help for the TRPCBroker Component
 
Context-sensitive Help for the TRPCBroker Component
Line 402: Line 402:
  
 
Broker Overview
 
Broker Overview
The RPC Broker is a bridge connecting the client application front-end on the workstation (e.g., Delphi GUI applications) to the M-based data and business rules on the server.
+
The RPC Broker is a bridge connecting the client application front-end on the workstation (e.g., Delphi GUI applications) to the M-based data and [[business rules~|Business Rules]] on the server.
  
  
Line 444: Line 444:
  
 
Developers creating Delphi GUI applications can use the TRPCBroker Component to connect. For each transaction, the application must set parameters and execute a call. Issues include:
 
Developers creating Delphi GUI applications can use the TRPCBroker Component to connect. For each transaction, the application must set parameters and execute a call. Issues include:
· Determine data types for input and return.
+
· Determine [[data types~|Data Types]] for input and return.
 
· Determine the kind of call to make.
 
· Determine the kind of call to make.
  
Line 518: Line 518:
 
In special cases, applications can use one of two types of Silent Login to log in users without the RPC Broker prompting for login information.
 
In special cases, applications can use one of two types of Silent Login to log in users without the RPC Broker prompting for login information.
  
Historical Information Regarding the 16-Bit BDK vs. 32-Bit BDK
+
[[Historical~|Historical]] Information Regarding the 16-Bit BDK vs. 32-Bit BDK
 
The following items should be noted when transitioning from the original 16-bit Broker Development Kit (BDK) V. 1T11 (i.e., Preview BDK released in October 1995) to the 32-bit BDK V. 1.1 (i.e., first released in September 1997):
 
The following items should be noted when transitioning from the original 16-bit Broker Development Kit (BDK) V. 1T11 (i.e., Preview BDK released in October 1995) to the 32-bit BDK V. 1.1 (i.e., first released in September 1997):
  
Line 565: Line 565:
  
  
By replacing the RPCBI.DLL that was distributed with the RPC Broker V. 1.0 with the BAPI32.DLL, the Client Manager is no longer required with the 32-bit version of the Broker. Configuration of programmer preferences is done via the Broker Programmer Preferences Program.
+
By replacing the RPCBI.DLL that was distributed with the RPC Broker V. 1.0 with the BAPI32.DLL, the Client Manager is no longer required with the 32-bit version of the Broker. [[Configuration~|Configuration]] of programmer preferences is done via the Broker Programmer Preferences Program.
  
 
  The RPCBI.DLL and Client Manager (i.e., CLMAN.EXE) installed with Broker V. 1.0 must not be removed from the VISTA/Broker directory on the client workstation. They are still required for any 16-bit Broker-based applications created using version 1.0 of the Broker (e.g., PCMM).
 
  The RPCBI.DLL and Client Manager (i.e., CLMAN.EXE) installed with Broker V. 1.0 must not be removed from the VISTA/Broker directory on the client workstation. They are still required for any 16-bit Broker-based applications created using version 1.0 of the Broker (e.g., PCMM).
Line 2,326: Line 2,326:
  
 
Description
 
Description
The PromptDivision property is available at run-time only. It should be set to True, if the user should be prompted for Division during Silent Login. The prompt will only occur if the user has multi-division access. This property should be set to False, if the prompt should not be displayed due to the manner in which the application is running. However, if set to False and multi-division access is a possibility, then the application must handle it in another way. For example, the application developer would do the following:
+
The PromptDivision property is available at run-time only. It should be set to True, if the user should be prompted for Division during Silent Login. The [[prompt~|Prompt]] will only occur if the user has multi-division access. This property should be set to False, if the [[prompt~|Prompt]] should not be displayed due to the manner in which the application is running. However, if set to False and multi-division access is a possibility, then the application must handle it in another way. For example, the application developer would do the following:
 
1. Set Login.PromptDivision to False.
 
1. Set Login.PromptDivision to False.
 
2. Set the Connected property to True to signon.
 
2. Set the Connected property to True to signon.
Line 2,906: Line 2,906:
  
 
Creating RPCs
 
Creating RPCs
You can create your own custom RPCs to perform actions on the M server and to retrieve data from the M server. Then you can call these RPCs from your client application. Creating an RPC requires you to perform the following two steps:
+
You can create your own custom RPCs to perform [[action~|Action]]s on the M server and to retrieve data from the M server. Then you can call these RPCs from your client application. Creating an RPC requires you to perform the following two steps:
 
· Write and test the M entry point that will be called by the RPC.
 
· Write and test the M entry point that will be called by the RPC.
 
· Add the RPC entry that invokes the M entry point, in the REMOTE PROCEDURE file (#8994).
 
· Add the RPC entry that invokes the M entry point, in the REMOTE PROCEDURE file (#8994).
Line 3,947: Line 3,947:
 
The functionality provided by GetServerInfo is not currently available through the RPC Broker 32-bit DLL interface. A future version of the RPC Broker will provide access to the GetServerInfo functionality for DLL users.
 
The functionality provided by GetServerInfo is not currently available through the RPC Broker 32-bit DLL interface. A future version of the RPC Broker will provide access to the GetServerInfo functionality for DLL users.
  
To work around this for now, when using the RPC Broker 32-bit DLL, you should prompt the user directly for the server and port to connect to.
+
To work around this for now, when using the RPC Broker 32-bit DLL, you should ~|Prompt]]prompt the user directly for the server and port to connect to.
  
 
DLL Exported Functions
 
DLL Exported Functions
Line 4,822: Line 4,822:
 
20002
 
20002
 
The server side of the application errored out.  The Kernel error trap has recorded the error.
 
The server side of the application errored out.  The Kernel error trap has recorded the error.
Resolution: Examine the Kernel error trap for more information and specific corrective actions.
+
Resolution: Examine the Kernel error trap for more information and specific corrective [[action~|Action]]s.
 
Signon was not completed
 
Signon was not completed
 
XWB_BadSignOn
 
XWB_BadSignOn
Line 4,837: Line 4,837:
 
20006
 
20006
 
This error occurs when an RPC does not have an associated version number. Each RPC must have a version number.
 
This error occurs when an RPC does not have an associated version number. Each RPC must have a version number.
Resolution: Contact the developers responsible for the application software to take corrective action.
+
Resolution: Contact the developers responsible for the application software to take corrective [[action~|Action]].
 
Remote procedure not registered to application
 
Remote procedure not registered to application
 
XWB_RpcNotReg
 
XWB_RpcNotReg
Line 5,123: Line 5,123:
  
 
Tutorial: Step 7 -- Associating IENs
 
Tutorial: Step 7 -- Associating IENs
When a user selects a terminal type entry in the list box, a typical action would be to retrieve the corresponding record and display its fields. The key to retrieving any VA FileMan record is knowing the IEN of the record. Thus, when a user selects an entry in the list box, you need to know the IEN of the corresponding VA FileMan entry. However, the list box items themselves only contain the name of each entry, not the IEN.
+
When a user selects a terminal type entry in the list box, a typical [[action~|Action]] would be to retrieve the corresponding record and display its fields. The key to retrieving any VA FileMan record is knowing the IEN of the record. Thus, when a user selects an entry in the list box, you need to know the IEN of the corresponding VA FileMan entry. However, the list box items themselves only contain the name of each entry, not the IEN.
  
 
The subscripting of items in the list box still matches the original subscripting of items returned in brkrRPCBroker1's Results property, as performed by the following code in Button1Click event handler:
 
The subscripting of items in the list box still matches the original subscripting of items returned in brkrRPCBroker1's Results property, as performed by the following code in Button1Click event handler:

Latest revision as of 18:26, 1 January 2013

This is a conversion of the RPC Broker Developer's Guide Broker.hlp file to mediawiki format using the helpdeco converter program converted to vistapedia.net by Ignacio Valdes of Astronaut, LLC The original formatting such as Table of Contents linking and screen shots is not present.

:Base broker.hlp>main
:Title RPC Broker Developer's Guide

1 RPC Broker V. 1.1 Developer's Guide
2 Overview
3 Introduction=introduction
3 Broker Overview=Broker_Overview
3 Orientation=Orientation
3 About this Version of the RPC Broker=About_this_version
3 What's New in the BDK=Whats_New_in_the_BDK
3 Developer Considerations=Developer_Considerations
3 Application Issues=Application_Level_Issues
3 Silent Login=Silent_Login
3 Context-sensitive Help for the TRPCBroker Component=ig_helpfile
2 RPC Broker Components and Classes
3 TRPCBroker Component=TRPCBroker
3 TXWBRichEdit Component=TXWBRichEdit_Component
3 TMult Class=TMult_Class
3 TParamRecord Class=TParamRecord_Class
3 TParams Class=TParams_Class
3 TVistaLogin Class=TVistaLogin_Class
3 TVistaUser Class=TVistaUser_Class
3 EBrokerError Exception=EBrokerError
3 Units
4 Hash Unit=Hash_unit
4 LoginFrm Unit=LoginFrm_Unit
4 MFunStr Unit=MFunStr_unit
4 RPCConf1 Unit=RPCConf1_unit
4 RpcSLogin Unit=RpcSLogin_Unit
4 SplVista Unit=SplVista_unit
4 TRPCB Unit=TRPCB_unit
4 TVCEdit Unit=TVCEdit_Unit
2 Remote Procedure Calls (RPCs)
3 Overview=rpc_overview
3 What Makes a Good RPC?=rpc_good
3 Creating RPCs=rpc_create
3 Using an Existing M API=Using_an_Existing_M_API
3 M Entry Point for an RPC
4 Relationship Between an M Entry Point and an RPC=rpc_routine_relationship
4 First Input Parameter=rpc_first_input_param
4 Return Value Types=rpc_return_value_types
4 Input Parameters=rpc_input_parameter_types
4 Examples=rpc_entry_point_examples
3 RPC Entry in the Remote Procedure File
4 RPC Entry in the Remote Procedure File=rpc_file_entry
4 RPC Version in the Remote Procedure File=RPC_Version_in_Remote_Procedure_File
4 Blocking an RPC in the Remote Procedure File=Blocking_an_RPC
4 Cleanup after RPC Execution=rpc_cleanup
4 Documenting RPCs=rpc_document
3 Executing RPCs from Clients
4 How to Execute an RPC from a Client=rpc_execute_from_client
4 RPC Security: How to Register an RPC=rpc_register
4 RPC Limits=RPC_limits
4 BrokerExample Online Code Example=BrokerExample
2 Other RPC Broker APIs
3 Overview=otherapi_Overview
3 Encryption Functions=otherapi_encrypt
3 GetServerInfo Function=otherapi_getserverinfo
3 M Emulation Functions=otherapi_m_emulation
3 VistA Splash Screen Procedures=otherapi_splash
3 $$BROKER^XWBLIB=otherapi_broker
3 $$RTRNFMT^XWBLIB=otherapi_rtrnfmt
3 XWB ARE RPCS AVAILABLE=XWB_ARE_RPCS_AVAILABLE
3 XWB IS RPC AVAILABLE=XWB_IS_RPC_AVAILABLE
3 XWB GET VARIABLE VALUE RPC=otherapi_getvarvalue
3 Running RPCs on a Remote Server
4 Options For Running RPCs on a Remote Server=Options_For_Running_RPCs_on_a_Remote_Server
4 Checking RPC Availability on a Remote Server=Checking_RPC_Availability_on_a_Remote_Server
4 XWB DIRECT RPC=XWB_DIRECT_RPC
4 XWB REMOTE RPC=XWB_REMOTE_RPC
4 XWB REMOTE STATUS CHECK=XWB_REMOTE_STATUS_CHECK
4 XWB REMOTE GETDATA=XWB_REMOTE_GETDATA
4 XWB REMOTE CLEAR=XWB_REMOTE_CLEAR
3 Deferred RPCs
4 Overview of Deferred RPCs=Overview_of_Deferred_RPCs
4 XWB DEFERRED RPC=XWB_DEFERRED_RPC
4 XWB DEFERRED STATUS=XWB_DEFERRED_STATUS
4 XWB DEFERRED GETDATA=XWB_DEFERRED_GETDATA
4 XWB DEFERRED CLEAR=XWB_DEFERRED_CLEAR
4 XWB DEFERRED CLEARALL=XWB_DEFERRED_CLEARALL
2 Debugging and Troubleshooting
3 Overview=debug_overview
3 How to Debug Your Application=debug
3 RPC Error Trapping=Error_Handling
3 Identifying the Listener Process on the Server=ID_Listener
3 Identifying the Handler Process on the Server=ID_Handler
3 Testing Your RPC Broker Connection=Testing_Connection
3 Client Timeout and Buffer Clearing=Buffer_Clearing
3 Memory Leaks=memory_leaks
2 Developer Utilities
3 RPC Broker Programmer Preferences=IDH_brokprogpref
2 Tutorial
3 Introduction=tut_intro
3 Advanced Preparation=tut_prep
3 Step  1: Create Application with an RPC Broker Component=tut_step1
3 Step  2: Get Server/Port=tut_step2
3 Step  3: Establish Broker Connection=tut_step3
3 Step  4: RPC Routine to List Terminal Types=tut_step4
3 Step  5: RPC to List Terminal Types=tut_step5
3 Step  6: Call the ZxxxTT LIST RPC=tut_step6
3 Step  7: Associate IENs=tut_step7
3 Step  8: Routine to Retrieve Terminal Types=tut_step8
3 Step  9: RPC to Retrieve Terminal Types=tut_step9
3 Step 10: Call Zxxx RETRIEVE RPC=tut_step10
3 Step 11: Register RPCs=tut_register
3 See Also: FileMan Delphi Components (FMDC)=tut_fmdc
3 Tutorial Source Code=tut_pascal
2 DLL Interface
3 Introduction=dll_intro
3 DLL Special Issues
4 RPC Results from DLL Calls=dll_results
4 GetServerInfo Function and the DLL=dll_getserverinfo
3 DLL Exported Functions
4 RPCBCall=dll_function_rpcbcall
4 RPCBCreate=dll_function_rpcbcreate
4 RPCBCreateContext=dll_function_rpcbcreatecontext
4 RPCBFree=dll_function_rpcbfree
4 RPCBMultItemGet=dll_function_rpcbmultitemget
4 RPCBMultPropGet=dll_function_rpcbmultpropget
4 RPCBMultSet=dll_function_rpcbmultset
4 RPCBMultSortedSet=dll_function_rpcbmultsortedset
4 RPCBParamGet=dll_function_rpcbParamGet
4 RPCBParamSet=dll_function_rpcbParamSet
4 RPCBPropGet=dll_function_rpcbpropget
4 RPCBPropSet=dll_function_rpcbpropset
3 Guidelines for C++
4 Overview=dll_cpp_intro
4 TRPCBroker C++ Class Methods=dll_cpp_methods
4 Initialize the Class=dll_cpp_init
4 Create Broker Instances=dll_cpp_create
4 Connect to the Server=dll_cpp_connect
4 Execute RPCs=dll_cpp_execute
4 Destroy Broker Instances=dll_cpp_destroy
3 Guidelines for C
4 Overview=dll_c_intro
4 Initialize—LoadLibrary and GetProcAddress=dll_c_init
4 Create Broker Components=dll_c_create
4 Connect to the Server=dll_c_connect
4 Execute RPCs=dll_c_execute
4 Destroy Broker Components=dll_c_destroy
3 Guidelines for Visual Basic
4 Overview=dll_vb_intro
4 Initialize=dll_vb_init
4 Create Broker Components=dll_vb_create
4 Connect to the Server=dll_vb_connect
4 Execute RPCs=dll_vb_execute
4 Destroy Broker Components=dll_vb_destroy

Introduction: RPC Broker V. 1.1 The RPC Broker is a client/server system within VA's Veterans Health Information Systems and Technology Architecture (VISTA) environment. It enables client applications to communicate and exchange data with M Servers.

This manual describes the development features of the RPC Broker. The emphasis is on using the RPC Broker in conjunction with Borland's Delphi software. However, the RPC Broker supports other development environments.

This manual provides a complete reference for development with the RPC Broker. For an overview of development with the RPC Broker component, see the "RPC Broker V. 1.1 Getting Started with the Broker Development Kit" manual.

This document is intended for the VISTA development community and Information Resource Management (IRM) staff. A wider audience of technical personnel engaged in operating and maintaining the Department of Veterans Affairs (VA) software might also find it useful as a reference. Broker Overview Orientation About this Version of the RPC Broker What's New in the BDK Developer Considerations Application Issues Silent Login Context-sensitive Help for the TRPCBroker Component

For the latest RPC Broker product information, please refer to the RPC Broker Home Page on the web at: http://vista.med.va.gov/broker/index.html.

About this Version of the RPC Broker This version of the Broker provides programmers with the capability to develop new VISTA client/server software using the Broker Delphi component (i.e., TRPCBroker) in the 32-bit environment.

This version of the RPC Broker includes the following patches (listed in sequence order):


Seq # Patch Subject Release Date

1 XWB*1.1*1 Some Small Fixes 02/18/98 2 XWB*1.1*2 Encryption, Data Collection, Agent 07/27/98 3 XWB*1.1*3 Security Log Problem (XWBSEC Routine) 01/06/99 4 XWB*1.1*5 RUM Support 03/31/99 5 XWB*1.1*7 Broker Listener/Available Slots 06/04/99 6 XWB*1.1*4 Updated BDK and Kernel Login Fixes 06/24/99 7 XWB*1.1*6 Eliminate Orphaned Server Jobs 09/09/99 8 XWB*1.1*8 GUI Multi-Division Support 12/10/99 9 XWB*1.1*9 Caché License Fix 01/24/00 10 XWB*1.1*11 Delphi V. 5 Support 01/24/00 11 XWB*1.1*15 Broker Command Error Fix 04/12/00 12 XWB*1.1*10 RPC Availability 08/04/00 13 XWB*1.1*12 Server to Server RPC's 08/04/00 14 XWB*1.1*18 XWB2HL7 Routine Fix 10/17/00 15 XWB*1.1*14 Release Source Code for BDK 10/17/00 16 XWB*1.1*20 RDV Proper Setup of DUZ 05/10/01 17 XWB*1.1*22 Name and Null Subscript Error 10/03/01 18 XWB*1.1*24 Correct Problem with Reading Registry 11/09/01 (Updated BDK, Delphi 4 and 5 versions only) 19 XWB*1.1*16 Read/Write Errors 02/06/02 20 XWB*1.1*27 Remote Data Request Processing 03/15/02 21 XWB*1.1*13 Silent Logon, Bug Fixes, & Delphi V. 6 (Current) Support (Updated BDK)


To develop VISTA applications in a 32-bit environment you must have Delphi V. 2.0 or greater. This version of the TRPCBroker component does not allow you to develop applications in Delphi V. 1.0. However, the Broker routines on the M server will continue to support VISTA applications previously developed in the 16-bit environment.

The default installation of the Broker creates a separate Broker Development Kit (BDK) directory (i.e., BDK32) that contains the required Broker files for development.

The Office of Information (OI) will support the Broker Development Kit running in the currently offered version of Delphi and the immediately previous version of Delphi. This level of support became effective 6/12/2000.

Sites may continue to use outdated versions of the RPC Broker Development Kit but do so with the understanding that support will not be available and that continued use of outdated versions will not afford features that may be essential to effective client/server operations in the VISTA environment. An archive of old (no longer supported) Broker Development Kits will be maintained at: http://vista.med.va.gov/broker/archives/index.html

What's New in the BDK What’s New Through May 2002?

Support for Delphi V. 6.0

As of Patch XWB*1.1*13, the BDK supports Delphi V. 6.0.


New TRPCBroker Component Properties

As of Patch XWB*1.1*13, the following properties are new with this version of the RPC Broker:

Property CurrentContext (Public) KerneLogIn (Published) LogIn (Public) OnRPCBFailure (Public) RPCBError (Public) ShowErrorMsgs (Published) User (Public)


Property (Previously Never Documented) Socket (Public)


See the "Historical Information Regarding the 16-Bit BDK vs. 32-Bit BDK" topic for properties and methods introduced with the RPC Broker 32-bit BDK. This topic also highlights disposition of the Client Manager and those properties and parameters that were obsolete and removed from the 32-bit version of the BDK.


New Classes (and their associated properties)

As of Patch XWB*1.1*13, the following classes are new with this version of the RPC Broker:

Classes TVistaLogin TVistaUser


New Types

As of Patch XWB*1.1*13, the following Type is new with this version of the RPC Broker:

Type TLoginMode TShowErorMsgs TOnLoginFailure TOnRPCBFailure


ESSO-aware TRPCBroker Component

As of Patch XWB*1.1*13, the TRPCBroker component is now Enterprise Single Sign-On (ESSO) aware.

For more information on ESSO, please consult the ESSO documentation.


New Component (and its associated property)

As of Patch XWB*1.1*13, the following component is new with this version of the RPC Broker:

Component TXWBRichEdit

This new component replaced the Introductory Text Memo component on the Login Form. It permits URLs to be identified and launched.


New Silent Login

As of Patch XWB*1.1*13, the RPC Broker now provides "Silent Login" capability. It provides functionality associated with the ability to make logins to a VISTA server without the RPC Broker asking for Access and Verify code information. Silent Login

Two types of Silent Login are provided with this version of the BDK, and the basis for a third future method is included as well. 1. One type of Silent Login uses Access and Verify codes provided by the application. This type of Silent Login may be necessary for an application that runs as a background task and repeatedly signs on for short periods. Another case would be for applications that are interactive with the user, but are running under conditions where they cannot provide a standard dialog window, such as that used by the Broker to request Access and Verify codes. Examples might be applications running on handheld devices or within a browser window. 2. The second type of Silent Login supported by the current patch utilizes a token obtained by one application that is passed along with other information as a command line argument to a second application that it is starting. The token is obtained from the VISTA server and remains valid for about twenty (20) seconds. When the newly started application sends this token during login the server identifies the same user and completes the login.

Due to the various conditions under which Silent Logins might be used, it was also necessary to provide options to the applications on error handling and processing. Applications that run as system services will crash if they attempt to show a dialog box. Similarly, applications running within web browsers are not permitted to show a dialog box or to accept windows messages. New properties have been provided to permit the application to handle errors in a number of ways.

As a part of the Silent Login functionality, the TVistaUser class providing basic user information was added. This class is used as a property by the TRPCBroker class and is filled with data following completion of the login process. This property and its associated data is available to all applications, whether they are using a Silent Login or not.


Newly Documented Deferred RPCs and Capability to Run RPCs on a Remote Server Deferred RPCs Running RPCs on a Remote Server


New Library Methods

The following library methods are new in the TVCEdit Unit: · ChangeVerify

function ChangeVerify(RPCBroker: TRPCBroker): Boolean; · SilentChangeVerify

function SilentChangeVerify(RPCBroker: TRPCBroker; OldVerify, NewVerify1, NewVerify2: String; var Reason: String): Boolean; · StartProgSLogin

procedure StartProgSLogin(const ProgLine: String; ConnectedBroker: TRPCBroker);


Modified Library Methods

The following library methods were modified: · CheckCmdLine

function CheckCmdLine(SLBroker: TRPCBroker): Boolean;

Changed from procedure to function with a Boolean return value. · GetServerInfo

As of Patch XWB*1.1*13, the GetServerInfo library function in the RpcConf1 unit, which can be used to select the desired Server name and ListenerPort, was modified to add a "new" button. This button can be used to add a new Server/ListenerPort combination to those available for selection. It will also accept and store a valid IP address, if no name is known for the location. This will permit those who have access to other Server/ListenerPort combinations that may not be available in the list on the current workstation to access them. However, they will still need a valid Access and Verify code to log on to the added location. · TParams

procedure Clear was moved from Private to Public. · TRPCB Unit

TOnLoginFailure = procedure (VistaLogin: TVistaLogin) of object;

Changed from Object: TObject, since this is what should be expected by the procedure if it is called.

TOnRPCBFailure = procedure (RPCBroker: TRPCBroker) of object;

Changed from Object: TObject, since this is what should be expected by the procedure if it is called.


Modified Broker Code for Multi-Instances

As of Patch XWB*1.1*13, the RPC Broker code was modified to permit an application to open two separate Broker instances with the same Server/ListenerPort combination, resulting in two separate partitions on the server. Previously, an attempt to open a second Broker instance ended up using the same partition. For this capability to be useful for concurrent processing, an application would have to use threads to handle the separate Broker sessions.

Although we believe there should be no problems, the RPC Broker is not yet guaranteed to be thread safe.


Source Code

As of Patch XWB*1.1*14, the BDK contains the Broker source code. The source code is located in the ..\BDK32\Source directory.

Modified BDK source code should NOT be used to create VISTA GUI applications. See Developer Considerations for details.

Not all methods and properties found in the source code are documented at this time. Only those documented methods and properties are guaranteed to be made backwards compatible in future versions of the BDK.


Design-time and Run-time packages

As of Patch XWB*1.1*14, the BDK now contains separate run-time and design-time packages. See Developer Considerations for details and compiling instructions.

Component Connect/Disconnect Behavior Connect

The first time one of the Broker components in your application connects, it will establish an actual connection with the server. The connection Record will be added to the list of all active connections for your application. This list is internal to the application and is completely under the control of the Broker component and is transparent to you. If another Broker component tries to connect to the same server/port, the existing connection Record will be found in the list and its socket will be shared. The new connection will also be added to this list. This process is repeated with each connection request.


Disconnect

When a Broker component disconnects, its connection Record is removed from the internal list of active connections. If it happens to be the last record for the particular server/port combination, the connection is actually closed. This scheme provides the illusion of multiple connections without "clogging up" the server.

Context-sensitive Help for the TRPCBroker Component The installation of the BDK automatically makes the Broker context-sensitive help available within Delphi for the TRPCBroker component.

You can select any property in the object inspector, press F1, and get help for that property. Also, you can select the TRPCBroker component on a form, press F1, and get help for the component.

Orientation Units

A unit is a Pascal source-code file. The BDK includes a number of units. This Help file documents some of the units provided, and details what parts of the BDK are declared in each unit.

Sometimes it is helpful to know in which unit a particular item, such as a type or routine, is declared in the BDK. This is because if you use the item in your own code, you may need to include the corresponding unit in your own Pascal unit's uses clause.


Classes, Objects, and Components

A class is a data type that wraps up code and data all in one bundle.

An object is a specific instance of that class with associated values.

A component is an object with additional properties, methods, and events that makes it suitable for specialized purposes.

The BDK includes classes, objects, and components. For each class, object, and component, this Help file lists the unit, declaration, properties, methods, and a description of how to use the class, object, or component.


Routines

Routines can either be functions or procedures. A function returns a value, and a procedure does not.

For topics in this Help file describing routines, the unit and declaration for each routine is listed, as well as a description of the routine is provided.


Types

A type defines the possible range of values for a property or a method. A number of types are declared in the BDK, which you may need to make use of yourself in your own code. For topics in this Help file describing types, the unit and declaration for each type, as well as a description of the type is also provided.

Broker Overview The RPC Broker is a bridge connecting the client application front-end on the workstation (e.g., Delphi GUI applications) to the M-based data and Business Rules on the server.


Client Side of the RPC Broker Server Side of RPC the Broker · Manages the connection to the client.

For details, please refer to the "RPC Broker Systems Manual." · TRPCBroker component allows Delphi applications to make RPCs to the server. · The Broker Dynamic Link Library (DLL) provides support for COTS/HOST client/server software. · Manages the connection to the client.

For details, please refer to the "RPC Broker Systems Manual." · Authenticates client machine. · Authenticates user. · Manages RPCs from the client, executes the M code, and passes back return values.


The Broker frees GUI developers from the details of the client-server connection and allows them to concentrate executing operations on the server.


Broker Call Steps

These steps present a basic outline of the events that go into a Broker call, starting with the initial client-server connection. Once the client machine and user are authenticated, any number of calls (Steps 3-5) can occur through the open connection.

GUI developer issues are noted for each step.

1. Authentication of client machine. When a client machine initiates a session, the Broker Listener on the server spawns a new job. The server then calls the client back to ensure that the client’s address is accurate. GUI Developer Issues: · None. This process is built into the Broker. See the "RPC Broker Systems Manual" for details.


2. Authentication of user. After the server connects back to the client machine, the user is asked for an Access and Verify code. GUI Developer Issues: · Applications must create a context for the user. This process checks the user’s access to individual RPCs associated with the application. · Developers must decide whether to enable Silent Login.


3. Client makes a Remote Procedure Call. GUI Developer Issues:

Developers creating Delphi GUI applications can use the TRPCBroker Component to connect. For each transaction, the application must set parameters and execute a call. Issues include: · Determine Data Types for input and return. · Determine the kind of call to make.

In addition to the TRPCBroker, other components are available. The VA FileMan Delphi components (FMDC) encapsulate the details of retrieving, validating and updating VA FileMan data within a Delphi application. For further information on the VA FileMan Delphi Components, see: http://vista.med.va.gov/fmdc/index.html

In the future, components may become available to encapsulate other VISTA functions.


4. RPC execution on server. GUI Developer Issues:

A Remote Procedure Call (RPC) is a defined call to M code that runs on an M server. For details, see the “RPCs ” section of this manual for details. Issues include: · Determine the best RPC. The BDK provides some RPC BROKER APIs. You may need to create your own RPC from scratch. In many cases, an existing M API can be wrapped into an RPC. · RPCs must be registered on the server so users of the GUI VISTA application will have access to them. See RPC Security: How to Register an RPC.


5. RPC returns information to the client. GUI Developer Issues: · Handling the return values, including any error messages.

Developer Considerations Source Code

RPC Broker Patch XWB*1.1*14 initiated release of Broker source code. The release of the source code does not affect how a developer uses the Broker Component or other parts of the BDK. Modified BDK source code should NOT be used to create VISTA GUI applications. Suggestions for changes to the BDK should be done via VISTA's National Online Information Sharing (NOIS) system (for bugs) or VISTA's Electronic Error and Enhancement Requests (E3R) system (for enhancements) for review and possible inclusion in another patch.

The source code is located in the ..\BDK32\Source directory.


Design-time and Run-time packages

As of Broker Patch XWB*1.1*14, the BDK now has separate run-time and design-time packages. There is no longer a VISTA Broker package. The new packages are XWB_Dxx and XWB_Rxx, where "D" means Design-time and "R" means Run-time and where "xx" is two digits indicating the version of Delphi with which it should be used (e.g., XWB_D50 is the design-time package for Delphi V. 5.0). The run-time package should not be used to create executables that depend on a separate XWB_Rxx.bpl installed on client workstations. There is no procedure in place at this time to reliably install the correct version of the run-time bpl on client workstations.

Do not compile your project so that it relies on dynamic linking with the BDK's run-time package; that is, do not check the "Build with runtime packages" box on the Packages tab of the Project Options dialog.


Reuse

Developers should be aware of existing resources that may be of use. These resources may be available nationally or through a particular project. Possibilities include: · Delphi components such as the VA FileMan Delphi components (FMDC). See: http://vista.med.va.gov/fmdc/index.html · RPC BROKER APIs · Existing M APIs

Application Issues Application Version Numbers

There may be a need to set or pass application version numbers. The suggested format is as follows: VersionNumber_PatchNumber(3 digits)


Thus, Patch 22 of Version 8.2 would be: 8.2022


Deferred RPCs

In order to increase efficiency, applications can run RPCs in the background.


Remote RPCs

In order to work with patient data across sites, applications can run RPCs on a remote server.


Blocking RPCs

Applications can install RPCs that should be used only in certain contexts. It is possible to block access to an RPC.


Silent Login

In special cases, applications can use one of two types of Silent Login to log in users without the RPC Broker prompting for login information.

Historical Information Regarding the 16-Bit BDK vs. 32-Bit BDK The following items should be noted when transitioning from the original 16-bit Broker Development Kit (BDK) V. 1T11 (i.e., Preview BDK released in October 1995) to the 32-bit BDK V. 1.1 (i.e., first released in September 1997):


Properties

The following properties were introduced with the 32-bit version of the RPC Broker:

Property RPCTimeLimit RPCVersion


Obsolete Properties

The following properties were previously included with the Broker component distributed with the BDK preview version. These properties were removed from the 32-bit version of the Broker, because they were obsolete:

Property Disposition ConnectMode Removed from the RPC Broker component (i.e., TRPCBroker) DisconnectMode Removed from the RPC Broker component (i.e., TRPCBroker) Protocol Removed from the RPC Broker component (i.e., TRPCBroker) Result Removed from the RPC Broker component (i.e., TRPCBroker) ServerJob Removed from the RPC Broker component (i.e., TRPCBroker)


Method

The following method was introduced with the 32-bit version of the RPC Broker: CreateContext


Obsolete PType Parameters

The following properties were previously included with the Broker component distributed with the BDK preview version. These properties were removed from the 32-bit version of the Broker because they were obsolete:

PType Parameter Disposition wordproc PType Removed (Not Supported) – The wordproc PType was used in the preview version of the RPC Broker BDK to pass text out of memo boxes, for example. However, the 32-bit version of the Broker uses list instead of wordproc. null PType Removed (Not Supported) – The null PType was used in the preview version of the RPC Broker BDK. It has also been removed. If your RPC has no input parameters, you should not use the Param property.


Client Manager (obsolete)

As of Version 1.1 of the RPC Broker, the Client Manager is no longer used. The Client Manager that was originally distributed with version 1.0 of the Broker provided two types of services: 1. It was used to invoke the RPCBI.DLL. 2. It was used by developers to set programmer preferences for using the TRPCBroker component.


By replacing the RPCBI.DLL that was distributed with the RPC Broker V. 1.0 with the BAPI32.DLL, the Client Manager is no longer required with the 32-bit version of the Broker. Configuration of programmer preferences is done via the Broker Programmer Preferences Program.

The RPCBI.DLL and Client Manager (i.e., CLMAN.EXE) installed with Broker V. 1.0 must not be removed from the VISTA/Broker directory on the client workstation. They are still required for any 16-bit Broker-based applications created using version 1.0 of the Broker (e.g., PCMM).


VA FileMan Delphi Components (FMDC)

Sample 16-bit VA FileMan Delphi Components (FMDC) were originally distributed with the preview version of the RPC Broker Developer Kit (BDK) released in October of 1995. The 32-bit RPC Broker V. 1.1 is not compatible with the 16-bit FMDC. However, the 32-bit FileMan Delphi V. 1.0 Components (i.e., available on the Intranet in January 1997) are compatible with version 1.1 of the Broker.

Please be advised that the VA FileMan Delphi Components are not distributed with the RPC Broker. For more information on VA FileMan Delphi components (FMDC), please go to the following web address: http://vista.med.va.gov/fmdc/index.html

ConnectMode Property (obsolete) Applied to TRPCBroker component

Declaration property ConnectMode: Enumerated;

Description Enhancements to how the Broker manages multiple connections make the ConnectMode property unnecessary. Consequently, it is being phased out. For now it has been "demoted" from published to public declaration. This means that this property will no longer be visible in the Object Inspector, however, the application will still compile. At run-time it is ignored.

If your application uses more than one Broker component, you should be aware of the component's connect and disconnect behavior.

This property was used to set the mode that determines when your application connected to the server. It could be set to one of the following values: AsNeeded: If the Broker component was not already connected to the server, this established a connection with the server when a call was made. This was the recommended setting. You can still manually connect the Broker component using the Connected property. ManualConnect: Required the developer to manually connect to the server by setting the Connected property to True. OnCreate: Connected to the server when the TRPCBroker component was created. This setting was ignored while in Delphi IDE.

The ConnectMode property that was made available with the RPC Broker Development Kit (BDK), released in October 1995, was removed from the 32-bit version of the RPC Broker component (i.e., TRPCBroker).

DisconnectMode Property (obsolete) Applied to TRPCBroker component

Declaration property DisconnectMode: Enumerated;

Description Enhancements to how the Broker manages multiple connections make the DisconnectMode property unnecessary. Consequently, it is being phased out. For now it has been "demoted" from published to public declaration. This means that this property will no longer be visible in the Object Inspector, however, the application will still compile. At run-time it is ignored.

If your application uses more than one Broker component, you should be aware of the component's connect and disconnect behavior.

This property was used to set the mode that determines when your application disconnected from the server. It could be set to one of the following values: ManualDisconnect: With this setting, the TRPCBroker did not try to disconnect from the server when it was destroyed. This setting was used when there were multiple Broker components in your application and it was not the last Broker component to be disconnected. OnDestroy: This setting was used to disconnect your application from the server when the TRPCBroker component was destroyed. This was used if you only had a single Broker component or it would be the last component to be disconnected when you had multiple Broker components.

The DisconnectMode property that was made available with the RPC Broker Development Kit (BDK), released in October 1995, was removed from the 32-bit version of the RPC Broker component (i.e., TRPCBroker).

Protocol Property (obsolete) Applied to TRPCBroker component

Description The Protocol property was originally put in the TRPCBroker component as a placeholder for future development, however, it was never used. Thus, it has been removed from this version of the TRPCBroker component.

The Protocol property that was made available with the RPC Broker Development Kit (BDK), released in October 1995, was removed from the 32-bit version of the RPC Broker component (i.e., TRPCBroker).

Result Property (obsolete) Applied to TRPCBroker component

Description The Result property was ambiguous with Delphi's reserved Result variable (i.e., used to return values from functions) and has been removed from this version of the Broker. What previously was returned in the Result property should now be returned in the 0th element of the Results Property referenced as Results[0].

The Result property that was made available with the RPC Broker Development Kit (BDK), released in October 1995, was removed from the 32-bit version of the RPC Broker component (i.e., TRPCBroker).

Developer's should not just do a search and replace of the word "Result", however. In some cases the word "Result" being referenced can be Delphi's legitimate use of the reserved word.

ServerJob Property (obsolete) Applied to TRPCBroker component

Declaration property ServerJob: String

Description The original intent of the ServerJob read-only property was to contain the $JOB of the corresponding process on the server. However, the RPC Broker has never populated this property with a value, and it is not supported in the 32-bit version of the Broker. Therefore, this property has been removed from the TRPCBroker component.

The ServerJob property that was made available with the RPC Broker Development Kit (BDK), released in October 1995, was removed from the 32-bit version of the RPC Broker component (i.e., TRPCBroker).

RPC Broker V. 1.1 Developer's Guide Contents Overview RPC Broker Components · TRPCBroker Component · TXWBRichEdit Component RPC Broker Classes · TMult Class · TParamRecord Class · TParams Class · TVistaLogin Class · TVistaUser Class Remote Procedure Calls (RPCs) Other RPC Broker APIs Debugging and Troubleshooting Developer Utilities Tutorial DLL Interface

TRPCBroker Component

Properties Methods Example Parent Class TRPCBroker = class(TComponent)

Unit TRPCB

Description

The TRPCBroker component (Trpcb.pas) provides VISTA application developers with all of the client/server-related functionality in one integrated component. Using the TRPCBroker component, an application can connect to the server by simply setting the Connected property to True. Remote procedures on the server can be executed by preparing the Param and RemoteProcedure properties and invoking either the Call, strCall or lstCall methods. The TRPCBroker component can be found on the Kernel tab in the component palette.

Properties inherited from the parent component (i.e., TComponent) are not discussed in this Help file (only those properties added to the parent component are described). For help on inherited properties, please see Delphi's documentation on the parent component (i.e., TComponent).

TRPCBroker Example The following example demonstrates how a TRPCBroker component can be used to connect to the server, execute various remote procedures, return the results and finally disconnect from the server. This example assumes that a TRPCBroker component already exists on the form as brkrRPCBroker1:


procedure TForm1.Button1Click(Sender: TObject); begin

 try
   {connect to the server}
   brkrRPCBroker1.Connected := True;
   //assign RPC name
   brkrRPCBroker1.RemoteProcedure := 'SOME APPLICATION RPC';
   {make the call}
   brkrRPCBroker1.Call;
   {display results}
   ListBox1.Items := brkrRPCBroker1.Results;
   {disconnect from the server}
   brkrRPCBroker1.Connected := False;
 except
   //put error handling code here
 end;

end;

TRPCBroker Properties TRPCBroker Legend ClearParameters ClearResults Connected CurrentContext DebugMode KernelLogIn ListenerPort LogIn OnRPCBFailure Param RemoteProcedure Results RPCBError RPCTimeLimit RPCVersion Server ShowErrorMsgs Socket User

TRPCBroker Methods TRPCBroker Call CreateContext lstCall pchCall strCall

ClearParameters Property Example Applies to TRPCBroker component

Declaration property ClearParameters: Boolean;

Description The ClearParameters design-time property gives the developer the option to clear the Param property following every invocation of the Call, strCall, or the lstCall methods. Setting ClearParameters to True clears the Param property.

Simple assignment of True to this property clears the Param property after every invocation of the Call, strCall, and lstCall methods. Thus, the parameters need only be prepared for the next call without being concerned about what was remaining from the previous call. By setting ClearParameters to False, the programmer can make multiple calls with the same Param property. It is also appropriate to set this property to False when a majority of the parameters in the Param property should remain the same between calls. However, minor changes to the parameters can still be made.

You can use the Broker Programmer Preferences Editor (BrokerProgPref.EXE located under the ..\BDK32 directory) to set the default value for this property when you add a TRPCBroker component to your form.

For a demonstration, please run the BrokerProgPref.EXE located in the ..\BDK32 directory.

ClearParameters Example The following program code sets the ClearParameters property to True:

procedure TForm1.Button1Click(Sender: TObject); begin

 brkrRPCBroker1.ClearParameters := True;

end;

ClearResults Property Example Applies to TRPCBroker component

Declaration property ClearResults: Boolean;

Description The ClearResults desing-time property gives the developer the option to clear the Results property prior to every invocation of the Call method. The strCall and lstCall methods are unaffected by this property. Setting ClearResults to True clears the Results property.

If this property is True, then the Results property is cleared before every invocation of the Call method, thus, assuring that only the results of the last call are returned. Conversely, a setting of False accumulates the results of multiple calls in the Results property.

You can use the Broker Programmer Preferences Editor (BrokerProgPref.EXE located under the ..\BDK32 directory) to set the default value for this property when you add a TRPCBroker component to your form.

For a demonstration, please run the BrokerProgPref.EXE located in the ..\BDK32 directory.

ClearResults Example The following program code sets the ClearResults property to True:

procedure TForm1.Button1Click(Sender: TObject); begin

 brkrRPCBroker1.ClearResults := True;

end;

Connected Property Example Applies to TRPCBroker component

Declaration property Connected: Boolean;

Description The Connected design-time property connects your application to the server: · Setting this property to True connects the application to the server · Setting it to False disconnects the application from the server

It is not necessary for your application to manually establish a connection to the server. This version of the Broker automatically connects and disconnects from the server. When you invoke an RPC, if a connection has not already been established, one will be established for you. However, a user will not be able to run your RPC unless a context has been created with the CreateContext method.

There are other advantages to establishing a connection manually. You can check if a connection is established, and branch accordingly depending on whether a connection was established or not. One good place to do this is in your application form's OnCreate event. For that event, you could include code like the following:


try brkrRPCBroker1.Connected:= True; except on EBrokerError do begin ShowMessage('Connection to server could not be established!'); Application.Terminate; end; end;


This code sets the TRPCBroker component's Connected property to True to establish a connection. If a Broker exception (i.e., EBrokerError) was raised (in which case the connection wasn't established), it provides a message to the user and calls the Terminate method to exit.

To verify that your application is connected to the server, check the value of the Connected property.

If a connected TRPCBroker component is destroyed (when the application is closed, for example), that component will first disconnect from the server. However, for programming clarity, it is advisable to disconnect your application from the server manually by setting the Connected property to False.

If your application uses more than one Broker component, you should be aware of the component's connect and disconnect behavior.

Connected Example The following program code sets the Connected property to True:


procedure TForm1.btnConnectClick(Sender: TObject); begin

 brkrRPCBroker1.Server := edtServer.Text;
 brkrRPCBroker1.ListenerPort := StrToInt(edtPort.Text);
 brkrRPCBroker1.Connected := True;

end;

The Server and ListenerPort properties must be set at design or run-time before setting the Connected property to True.

DebugMode Property Applies to TRPCBroker component

Declaration property DebugMode: Boolean;

Description The DebugMode design-time property controls how the server process should be started. The default setting is False.

A setting of False starts the server in the usual manner, as a background process.

For debugging purposes, it can be very helpful to set break points, run the server process interactively, and step through the execution. For those situations, set this property to True. When the TRPCBroker component connects with this property set to True, you get a dialog window indicating your workstation Internet Protocol (IP) address and the port number.

At this point you should switch over to the server, enter any break points that you wish, issue the debug command (e.g., ZDEBUG in DSM), and start the following server process:

>D EN^XWBTCP

You will be prompted for the workstation Internet Protocol (IP) address and the port number. After entering the information, switch over to the client application and click on the OK button of the dialog window.

For more information, see How to Debug Your Application.

ListenerPort Property Example Applies to TRPCBroker component

Declaration property ListenerPort: Integer;

Description The ListenerPort design-time property gives the developer the ability to select the Listener port on the server. It must always be set before connecting to the server.

If one server computer has two or more environments (UCIs) that support client/server applications (e.g., Test and Production accounts), the Broker Listener processes must be listening on unique ports. Thus, you must specify which Listener port to use when you start the Listener on the server. Consequently, if you have more than one Listener running on the same server, the application needs to specify the correct Listener for its connection request. This is accomplished using the ListenerPort property.

After the initial connection, the server connection is moved to another port number (i.e., Socket), which is used for the remainder of the session.

You can use the Broker Programmer Preferences Editor (BrokerProgPref.EXE located under the ..\BDK32 directory) to set the default value for this property when you add a TRPCBroker component to your form.

For a demonstration, please run the BrokerProgPref.EXE located in the ..\BDK32 directory.

ListenerPort Example The following program code demonstrates using the ListenerPort property:


procedure TForm1.btnConnectClick(Sender: TObject); begin

 brkrRPCBroker1.ListenerPort := 9001;
 brkrRPCBroker1.Connected := True;

end;

Param Property Example Applies to TRPCBroker component

Declaration property Param: TParams;

Description The Param property is available at run-time only. It holds all of the parameters that the application needs to pass to the remote procedure using the Call, strCall, or lstCall methods.

Param is a zero-based array of TParamRecord. You don't need to explicitly allocate any memory for the Param property. Simple reference to an element or a value assignment ( := ) dynamically allocates memory as needed. You should start with the 0th element and proceed in sequence. Do not skip elements.

Each element in the Param array has the following properties: Mult PType Value

Passing multiple parameters of PType list in one remote procedure call (RPC) is not supported at this time. Only one list parameter can be passed to an RPC, and it must be the last parameter in the actual list.


The Param relationship to the TRPCBroker component is as follows:

The TRPCBroker component contains the Param property (i.e., TParams class).

The TParams class contains the ParamArray property (array [I:integer]: TParamRecord class).

The TParamRecord class contains the Mult property (i.e., TMult class).

The TMult class contains the MultArray property (array[S: string]: string).

The MultArray property internally uses a TStringList in which each element’s object is a TString.

If the remote procedure on the server does not require any incoming parameters, applications can pass an empty Param property. The client application merely sets the RemoteProcedure property and makes the call. If the Param property retains a value from a previous call, it can be cleared using the ClearParameters property. Thus, it is possible to make a call without passing any parameters.

The following restrictions apply with the Param property:

1. You are not allowed to "skip" passing parameters, such as TAG^ROUTINE(1,,3), where you can skip passing the second parameter in DSM code. If you have fewer elements in your Param array than exist as input parameters in your RPC, the subsequent parameters will not be passed to the RPC.

2. Passing multiple array parameters in one remote procedure call is not supported at this time. Only one array parameter can be passed to an RPC, and it must be the last parameter in the actual list.

For a demonstration using the Param property, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.

Param Example The following program code demonstrates how the Param property of a TRPCBroker component is referenced and filled with two parameters that the remote procedure expects:


procedure TForm1.Button1Click(Sender: TObject); begin

 {first parameter is a single string}
 brkrRPCBroker1.Param[0].Value := '05/01/97';
 brkrRPCBroker1.Param[0].PType := literal;
 {second parameter is a list}
 brkrRPCBroker1.Param[1].Mult['"NAME"'] := 'SMITH,JOHN';
 brkrRPCBroker1.Param[1].Mult['"SSN"'] := '123-45-6789';
 brkrRPCBroker1.Param[1].PType := list;

end;

For a demonstration using the Param property, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.

EBrokerError Unit TRPCB

Description

The EBrokerError is an exception raised by the TRPCBroker component. This exception is raised when an error is encountered when communicating with the server. You should use a try…except block around all server calls to handle any EbrokerError exceptions that may occur.

For example:


try brkrRPCBroker1.Connected:= True; except on EBrokerError do begin ShowMessage('Connection to server could not be established!'); Application.Terminate; end; end;

For descriptions/resolutions to specific error messages that can be displayed by EBrokerError, please refer to the Broker Error Messages topic.

TParamRecord Class Properties Example Unit TRPCB

Description

The TParamRecord class is used to hold all of the information on a single RPC parameter. Depending on the type of the parameter needed, different properties are used. The PType property is always used to let the Broker on the server know how to interpret the parameter. For a single value parameter, the Value property should be used. In the case of a list or a word-processing text, use the Mult property.

The TParamRecord relationship to the TRPCBroker component is as follows:

The TRPCBroker component contains the Param property (i.e., TParams class).

The TParams class contains the ParamArray property (array [I:integer]: TParamRecord class).

The TParamRecord class contains the Mult property (i.e., TMult class).

The TMult class contains the MultArray property (array[S: string]: string).

The MultArray property internally uses a TStringList in which each element’s object is a TString.

Developers should rarely have a need to use TParamRecord by itself in their code. TParamRecord is the type of the elements in the ParamArray, default array property of the TRPCBroker component Param property. This means that when you are working with a Param[x] element, you are in reality working with an instance of TParamRecord.

TParamRecord Example The following program code demonstrates how you can use a TParamRecord variable to save a copy of a single parameter of a TRPCBroker component. This example assumes that prior to calling this procedure, a TRPCBroker variable has been created and some parameters have been set up. Pay close attention to how properties are copied one at a time. This is the only way that a separate copy could be created. If you try to simply assign one of the TRPCBroker parameters to the TParamRecord variable, you’ll simply re-point the TParamRecord variable to that parameter:


procedure TForm1.Button1Click(Sender: TObject); var

 ParamRecord: TParamRecord;

begin

 {Create ParamRecord. Make Form1 its owner}
 ParamRecord := TParamRecord.Create(Form1);
 {Store properties one at a time}
 ParamRecord.Value := RPCBroker.Param[0].Value;
 ParamRecord.PType := RPCBroker.Param[0].PType;
 {This is how to copy a Mult}
 ParamRecord.Mult.Assign(RPCBroker.Param[0].Mult);

end;

TParamRecord Properties TParamRecord Mult PType Value

Value Property Example Applies to TParamRecord class

Declaration property Value: String;

Description The Value design-time property is used to pass either a single string or a single variable reference to the server, depending on the PType.

Value Example The following program code demonstrates a couple of different uses of the Value property. Remember that each Param[x] element is really a TParamRecord-type class.


procedure TForm1.Button1Click(Sender: TObject); begin

 with brkrRPCBroker1 do begin
   RemoteProcedure := 'SET NICK NAME';
   {A variable reference}
   Param[0].Value := 'DUZ';
   Param[0].Ptype := reference;
   {A string}
   Param[1].Value := edtNickName.Text;
   Param[1].Ptype := literal;
   Call;
 end;

end;

PType Property Example Applies to TParamRecord class

Declaration property PType: TParamType;

Description (PType is a property of the TParamRecord used in the Param property.)

The PType design-time property determines how the parameter will be interpreted and handled by the Broker.

Value Definition literal The server receives the contents of the corresponding Value property as one string or one number. reference The server receives the contents of the corresponding Value property as a name of a variable defined on the server. Using indirection, the Broker on the server will resolve this parameter before handing it off to the application. list This value is used whenever an application wants to send a list of values to the server. In this case, the contents of the corresponding Mult property is sent, while the Value property is ignored. undefined The Broker uses this value internally. It should not be used by an application.


For instance, if you need to pass an empty string to the remote procedure call (RPC), the Value property should be set to (i.e., null) and the PType to literal. Using reference, a programmer can pass an M variable (e.g., DUZ) without even knowing its value. However, If the M variable being referenced is not defined on the server, a run-time error will occur. When passing a list to an RPC: set the PType to list, populate the Mult property, and don't put anything into the Value property (in this case, Value is ignored).

For a demonstration using PType, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.

PType Example The following program code demonstrates a couple of different uses of the PType property. Remember that each Param[x] element is really a TParamRecord-type class.


procedure TForm1.Button1Click(Sender: TObject); begin

 with brkrRPCBroker1 do begin
   RemoteProcedure := 'SET NICK NAME';
   Param[0].Value := 'DUZ';
   Param[0].PType := reference;
   Param[1].Value := edtNickName.Text;
   Param[1].PType := literal;
   Call;
 end;

end;

For a demonstration using PType, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.

TParamType Unit TRPCB

Declaration TParamType = (literal, reference, list, undefined);

Description

The TParamType type defines the possible values of the RPC parameter type (PType property of TParamRecord class).

Use of the undefined TParamType in applications is not supported. It exists for the RPC Broker’s internal use only.

Mult Property Example Applies to TParamRecord class

Declaration property Mult: TMult;

Description (Mult is a property of the TParamRecord used in the Param property.)

The Mult design-time property of a TParamRecord class, which is the type of each TRPCBroker component’s Param[x] element, can be used to pass a string-subscripted array of strings to the server. For example, if you need to pass a patient's name and SSN to a remote procedure, you could pass them as two separate parameters as PType literals, or you could pass them in one parameter using the Mult property as a PType list. If one is being sent, a Mult must be the last element in the Param array.

Mult Example The following program code demonstrates how the Mult property can be used to pass several data elements to the server in one parameter:


procedure TForm1.Button1Click(Sender: TObject); begin

 with brkrRPCBroker1 do begin
   Param[0].PType :=list;
   Param[0].Mult['"NAME"'] := 'DOE,JOHN';
   Param[0].Mult['"SSN"'] := '123456789';
   RemoteProcedure := 'SETUP PATIENT INFO';
   Call;
 end;

end;


Assuming variable P1 is used on the server to receive this array, it would look like the following:


P1("NAME")=DOE,JOHN P1("SSN")=123456789

RemoteProcedure Property Example Applies to TRPCBroker component

Declaration property RemoteProcedure: TRemoteProc;

Description The RemoteProcedure design-time property should be set to the name of the remote procedure call entry in the REMOTE PROCEDURE file (#8994).

RemoteProcedure Example The following program code demonstrates using the RemoteProcedure property:


procedure TForm1.Button1Click(Sender: TObject); begin

 brkrRPCBroker1.RemoteProcedure := 'MY APPLICATION REMOTE PROCEDURE';
 brkrRPCBroker1.Call;

end;

Results Property Example Applies to TRPCBroker component

Declaration property Results: Tstrings;

Description The Results design-time property contains the results of a Call method. In the case where the RPC returns a single value, it will be returned in Results[0]. If a call returns a list of values, the Results property will be filled in the order the list collates on the server. The Results property can only contain values of array elements – subscripts are not returned.

For example:

On the server, the M routine constructs the list in the following sequence:

S LIST("CCC")="First" S LIST(1)="Second" S LIST("AAA")="Third" S LIST(2)="Fourth"


Before Broker returns the list to the client, M will re-sort it in alphabetical order:

LIST(1)="Second" LIST(2)="Fourth" LIST("AAA")="Third" LIST("CCC")="First"


On the client, the Results property will contain the following:

brkrRPCBroker1.Results[0]=Second brkrRPCBroker1.Results[1]=Fourth brkrRPCBroker1.Results[2]=Third brkrRPCBroker1.Results[3]=First

Results Example The following program code demonstrates using the Results property:


procedure TForm1.btnSendClick(Sender: TObject); begin

 {clears Results between calls}
 brkrRPCBroker1.ClearResults := True;
 {the following code returns a single value}
 brkrRPCBroker1.RemoteProcedure := 'SEND BACK SOME SINGLE VALUE';
 brkrRPCBroker1.Call;
 Label1.Caption := 'Value returned is: ' + brkrRPCBroker1.Results[0];
 {the following code returns several values}
 brkrRPCBroker1.RemoteProcedure := 'SEND BACK LIST OF VALUES';
 brkrRPCBroker1.Call;
 ListBox1.Items := RPCBroker.Results;

end;

RPCTimeLimit Property Example Applies to TRPCBroker component

Declaration property RPCTimeLimit: Integer;

Description The RPCTimeLimit property is a public integer property that is available at run-time only. It specifies the length of time a client will wait for a response from an RPC. The default and minimum value of this property is 30 seconds. If an RPC is expected to take more than 30 seconds to complete, adjust the RPCTimeLimit property accordingly. However, it is not advisable to have an RPCTimeLimit that is too long. Otherwise, the client-end of the application will appear to "hang", if the server doesn’t respond in a timely fashion.

RPCTimeLimit Example The following program code demonstrates using the RPCTimeLimit property:


procedure TForm1.Button1Click(Sender: TObject); var

 intSaveRPCTimeLimit: integer;

begin

 brkrRPCBroker1.RemoteProcedure := 'GET ALL LAB RESULTS';
 brkrRPCBroker1.Param[0].Value := 'DFN';
 brkrRPCBroker1.Param[0].PType := reference;
 {save off current time limit}
 intSaveRPCTimeLimit := brkrRPCBroker1.RPCTimeLimit;
 {can take up to a minute to complete}
 brkrRPCBroker1.RPCTimeLimit := 60;
 brkrRPCBroker1.Call;
 {restore previous time limit}
 brkrRPCBroker1.RPCTimeLimit := intSaveRPCTimeLimit;

end;

RPCVersion Property Example Applies to TRPCBroker component

Declaration property RPCVersion: String;

Description The RPCVersion design-time property is a published string type property used to pass the version of the RPC. This can be useful for backward compatibility.

As you introduce new functionality into an existing RPC, your RPC can branch into different parts of the code based on the value of the RPCVersion property. The Broker sets the XWBAPVER variable on the server to the contents of the RPCVersion property. This property cannot be empty and defaults to "0" (zero).

You may wish to use the application version number in the RPCVersion property. See Application Issues for a suggested method for constructing version numbers.

RPCVersion Example In the following example, an RPC is first called with two parameters that will be added together and the sum returned to the client. Again, this same RPC is called with the same parameters, however, this time it uses a different RPC version value. Thus, the two numbers are simply concatenated together and the resulting string is returned:


On the client:

procedure TForm1.Button1Click(Sender: TObject); begin

 {make sure the results get cleared}
 brkrRPCBroker1.ClearResults := True;
 {just re-use the same parameters}
 brkrRPCBroker1.ClearParameters := False;
 brkrRPCBroker1.RemoteProcedure := 'MY APPLICATION REMOTE PROCEDURE';
 brkrRPCBroker1.Param[0].Value := '333';
 brkrRPCBroker1.Param[0].PType := literal;
 brkrRPCBroker1.Param[1].Value := '444';
 brkrRPCBroker1.Param[1].PType := literal;
 brkrRPCBroker1.Call;
 {the result will be 777}
 Label1.Caption := 'Result of the call: ' + brkrRPCBroker1.Results[0];
 brkrRPCBroker1.RPCVersion := '2';
 brkrRPCBroker1.Call;
 {the result will be 333444}
 Label2.Caption := 'Result of the call: ' + brkrRPCBroker1.Results[0];

end;


On the server:

TAG(RESULT,PARAM1,PARAM2) ;Code for MY APPLICATION REMOTE PROCEDURE IF XWBAPVER<2 SET RESULT=PARAM1+PARAM2 ELSE SET RESULT=PARAM1_PARAM2 QUIT RESULT

Server Property Example Applies to TRPCBroker component

Declaration property Server: String;

Description The Server design-time property contains the name or Internet Protocol (IP) address of the server computer. If the name is used instead of the IP address, Windows Winsock should be able to resolve it. Winsock can resolve a name to an IP address either through the Domain Name Service (DNS) or by looking it up in the HOSTS file on the client workstation. In the case where the same name exists in the DNS and in the HOSTS file, the HOSTS file entry takes precedence. Changing the name of the server while the TRPCBroker component is connected disconnects the TRPCBroker component from the previous server.

You can use the Broker Programmer Preferences Editor (BrokerProgPref.EXE located under the ..\BDK32 directory) to set the default value for this property when you add a TRPCBroker component to your form.

For a demonstration, please run the BrokerProgPref.EXE located in the ..\BDK32 directory.

Server Example The following program code demonstrates using the Server property:


procedure TForm1.btnConnectClick(Sender: TObject); begin

 brkrRPCBroker1.ListenerPort := 9200;
 brkrRPCBroker1.Server := 'DHCPSERVER';
 brkrRPCBroker1.Connected := True;

end;

Call Method Example procedure Call;

This method executes a remote procedure on the server and returns the results in the Results property. Call expects the name of the remote procedure and its parameters to be set up in the RemoteProcedure and Param properties respectively. If ClearResults is True, then the Results property is cleared before the call. If ClearParameters is True, then the Param property is cleared after the call finishes.

See RPC Limits for information about the size of parameters and results that can be passed to and returned from the TRPCBroker component.

Whenever the Broker makes a call to the server, if the cursor is crDefault, the cursor is automatically changed to the hourglass symbol as seen in other Microsoft-compliant software. If the application has already modified the cursor from crDefault to something else, the Broker will not change the cursor.

For a demonstration using the Call method, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.

Call Example The following program code demonstrates the use of the Call method in a hypothetical example of bringing back demographic information for a patient and then displaying the results in a memo box:


procedure TForm1.Button1Click(Sender: TObject); begin

 brkrRPCBroker1.RemoteProcedure := 'GET PATIENT DEMOGRAPHICS';
 brkrRPCBroker1.Param[0].Value := 'DFN';
 brkrRPCBroker1.Param[0].PType := reference;
 brkrRPCBroker1.Call;
 Memo1.Lines := brkrRPCBroker1.Results;

end;

For a demonstration using the Call method, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.

CreateContext Method Example function CreateContext(strContext: string): boolean;

You can use the CreateContext method of the TRPCBroker component to create a context for your application. To create context, pass an option name in the strContext parameter. If the function returns True, a context was created, and your application can use all RPCs entered in the option's RPC multiple. If the TRPCBroker component is not connected at the time context is created, a connection will be established. If for some reason a context could not be created, the CreateContext method will return False.

Since context is nothing more than a client/server “B”-type option in the OPTION file (#19), standard MenuMan security is applied in establishing a context. Therefore, a context option can be granted to user(s) exactly the same way as regular options are done using MenuMan. Before any RPC can run, it must have a context established for it to on the server. Thus, all RPCs must be registered to one or more “B”-type option(s). This plays a major role in Broker security.

A context cannot be established for the following reasons: · The user has no access to that option. · The option is temporarily out of order.


An application can switch from one context to another as often as it needs to. Each time a context is created the previous context is overwritten.

See the CurrentContext property for information about saving off the current context in order to temporarily create a different context and then restore the previous context.

See RPC Limits for information about the size of parameters and results that can be passed to and returned from the TRPCBroker component.

Whenever the Broker makes a call to the server, if the cursor is crDefault, the cursor is automatically changed to the hourglass symbol as seen in other Microsoft-compliant software. If the application has already modified the cursor from crDefault to something else, the Broker will not change the cursor.

For a demonstration that creates an application context, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.

CreateContext Example The following program code demonstrates the use of the CreateContext method:


procedure TForm1.Button1Click(Sender: TObject); begin

 brkrRPCBroker1.Connected := True;
 if brkrRPCBroker1.CreateContext('MY APPLICATION') then
   Label1.Caption := 'Context MY APPLICATION was successfully created.'
 else
   Label1.Caption := 'Context MY APPLICATION could not be created.';

end;

For a demonstration that creates an application context, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.

lstCall Method Example procedure lstCall(OutputBuffer: Tstrings);

This method executes a remote procedure on the server and returns the results into the passed Tstrings- or TStringList-type variable, which you create outside of the call. It is important to free the memory later. lstCall expects the name of the remote procedure and its parameters to be set up in the RemoteProcedure and Param properties respectively. The Results property is not affected by this call. If ClearParameters is True, then the Param property is cleared after the call finishes.

See RPC Limits for information about the size of parameters and results that can be passed to and returned from the TRPCBroker component.

Whenever the Broker makes a call to the server, if the cursor is crDefault, the cursor is automatically changed to the hourglass symbol as seen in other Microsoft-compliant software. If the application has already modified the cursor from crDefault to something else, the Broker will not change the cursor.

For a demonstration using the lstCall method, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.

lstCall Example The following program code demonstrates the use of the lstCall method in a hypothetical example of bringing back a list of user's keys and automatically filling a list box with data:


procedure TForm1.Button1Click(Sender: TObject); begin

 brkrRPCBroker1.RemoteProcedure := 'GET MY KEYS';
 brkrRPCBroker1.lstCall(ListBox1.Items);

end;

For a demonstration using the lstCall method, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.

strCall Method Example function strCall: string;

This method executes a remote procedure on the server and returns the results as a value of a function. The strCall method expects the name of the remote procedure and its parameters to be set up in the RemoteProcedure and Param properties respectively. The Results property is not affected by this call. If ClearParameters is True, then the Param property is cleared after the call finishes.

See RPC Limits for information about the size of parameters and results that can be passed to and returned from the TRPCBroker component.

Whenever the Broker makes a call to the server, if the cursor is crDefault, the cursor is automatically changed to the hourglass symbol as seen in other Microsoft-compliant software. If the application has already modified the cursor from crDefault to something else, the Broker will not change the cursor.

For a demonstration using the strCall method, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.

strCall Example The following program code demonstrates the use of the strCall method in a hypothetical example of bringing back the name of the user currently logged on and automatically displaying it in a label:


procedure TForm1.Button1Click(Sender: TObject); begin

 brkrRPCBroker1.RemoteProcedure := 'GET CURRENT USER NAME';
 Label1.Caption := brkrRPCBroker1.strCall;

end;

For a demonstration using the strCall method, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.

TMult Class Properties Methods Example Unit TRPCB

Description

The TMult class is used whenever a list of multiple values needs to be passed to a remote procedure call (RPC) in a single parameter. The Mult property of a parameter is of TMult type. The information put in the TMult variable is really stored in a TStringList, but the access methods (used to read and write) take strings as subscripts and provide the illusion of a string-subscripted array.

It’s important to note that items in a TMult class may or may not be sorted. If the Sorted property is False (default), then the elements will be stored in the order they are added. If Sorted is True, items will be stored in ascending alphabetical order by subscripts.

If you attempt to reference an element by a nonexistent subscript you will get an error in form of a Delphi exception. Don’t forget that M syntax dictates that all strings must be surrounded by double quotes. So, if your goal is to pass a string subscripted array of strings using TMult as a parameter to an RPC on the M server, don’t forget to surround each of the subscripts and their associated values with double quotes (“). Otherwise, M will assume that you’re passing a list of variables and will attempt to reference them, which is probably not what you want.

TMult Example The following program code demonstrates how to store and retrieve elements from a TMult variable:


procedure TForm1.Button1Click(Sender: TObject); var

 Mult: TMult;
 Subscript: string;

begin

 {Create Mult. Make Form1 its owner}
 Mult := TMult.Create(Form1);
 {Store element pairs one by one}
 Mult['First'] := 'One';
 Mult['Second'] := 'Two';
 {Use double quotes for M strings}
 Mult['"First"'] := '"One"';
 {Label1.Caption will get "One"}
 Label1.Caption := Mult['"First"'];
 {Error! 'Third' subscripted element was never stored}
 Label1.Caption := Mult['Third'];

end;

TMult Properties TMult Count First Last Sorted

TMult Methods TMult Assign Order Position Subscript

Count Property Example Applies to TMult class

Declaration property Count: Word;

Description The Count design-time property contains the number of items in a TMult class. If TMult class is empty, Count will be zero.

Count Example The following program code displays the number of items in a Mult class in the caption of a label when the user clicks the CountItems button:

procedure TForm1.CountItemsClick(Sender: TObject); begin

 Label1.Caption := 'There are ' + IntToStr(Mult.Count) +
   ' items in the Mult.';

end;

First Property Example Applies to TMult class

Declaration property First: String;

Description The First design-time property contains the subscript of the first item in a TMult class. The first item is always in the 0th Position. You can think of the First property as a short cut to executing the TMult.Order(‘’,1) method. If a TMult variable does not contain any items, the First property will be empty.

First Example The following program code displays the subscript and value of the first item in a Mult variable in the caption of a label when the user clicks the GetFirst button:


procedure TForm1.GetFirstClick(Sender: TObject); var

 Mult: TMult;
 Subscript: string;

begin

 {Create Mult. Make Form1 its owner}
 Mult := TMult.Create(Form1);
 Mult['Fruit'] := 'Apple';
 {Store element pairs one by one}
 Mult['Vegetable'] := 'Potato';
 Label1.Caption := 'The subscript of the first element: ' + Mult.First + ', and its value: ' + Mult[Mult.First];

end;

Last Property Example Applies to TMult class

Declaration property Last: String;

Description The Last design-time property contains the subscript of the last item in a TMult class. The last item is always in count-1 Position. You can think of the Last property as a short cut to executing the TMult.Order(‘’,-1) method. If a TMult variable does not contain any items, the Last property will be empty.

Last Example The following program code displays the subscript and value of the last item in a Mult variable in the caption of a label when the user clicks the GetLast button:


procedure TForm1.GetLastClick(Sender: TObject); var

 Mult: TMult;
 Subscript: string;

begin

 {Create Mult. Make Form1 its owner}
 Mult := TMult.Create(Form1);
 Mult['Fruit'] := 'Apple';
 {Store element pairs one by one}
 Mult['Vegetable'] := 'Potato';
 Label1.Caption := 'The subscript of the last element: ' + Mult.Last +
   ', and its value: ' + Mult[Mult.Last];

end;

Sorted Property Example Applies to TMult class

Declaration property Sorted: Boolean;

Description The Sorted design-time property value determines the order of the items in a TMult variable. If Sorted is True, the items are sorted in ascending order of their string subscripts. If Sorted is False (default), the items are unsorted, and will appear in the order they were added. Keep in mind that changing Sorted from False to True will irreversibly sort the list so that changing Sorted back to False will not put the list back in its original order, unless the original order was already sorted of course.

Sorted Example The following program code demonstrates the effect the Sorted property has on a TMult variable. Notice that setting Sorted back to False does not revert the list to its unsorted order: 1. Start a new application. 2. Drop one memo and one button on the form. Arrange controls as in the figure below. 3. Copy the following code to the Button1.OnClick event:


procedure TForm1.Button1Click(Sender: TObject); var

 Mult1: TMult;
 Subscript: string;

begin

 //Create Mult1. Make Form1 its owner
 Mult1 := TMult.Create(Form1);
 //Fill Mult1 with some strings
 Mult1['First'] := 'One';
 Mult1['Second'] := 'Two';
 Mult1['Third'] := 'Three';
 Mult1['Fourth'] := 'Four';
 Mult1['Fifth'] := 'Five';
 //configure memo box for better display
 Memo1.Font.Name := 'Courier';
 Memo1.ScrollBars := ssVertical;
 Memo1.Lines.Clear;
 Memo1.Lines.Add('Natural order:');
 //set a starting point
 Subscript := ;
 repeat
   //get next Mult element
   Subscript := Mult1.Order(Subscript, 1);
   //if not the end of list
   if Subscript <>  then
     //display subscript – value
     Memo1.Lines.Add(Format('%10s', [Subscript]) + ' - ' + Mult1[Subscript])
 //stop when reached the end
 until Subscript = ;
 //list will now be sorted alphabetically
 Mult1.Sorted := True;
 Memo1.Lines.Add();
 Memo1.Lines.Add('Sorted order:');
 //set a starting point
 Subscript := ;
 repeat
   //get next Mult element
   Subscript := Mult1.Order(Subscript, 1);
   //if not the end of list
   if Subscript <>  then
     //display subscript – value
     Memo1.Lines.Add(Format('%10s', [Subscript]) + ' - ' + Mult1[Subscript])
 //stop when reached the end
 until Subscript = ;
 //existing entries will remain in sorted order
 Mult1.Sorted := False;
 Memo1.Lines.Add();
 Memo1.Lines.Add('Unsorted order:');
 //set a starting point
 Subscript := ;
 repeat
   //get next Mult element
   Subscript := Mult1.Order(Subscript, 1);
   //if not the end of list
   if Subscript <>  then
     //display subscript – value
     Memo1.Lines.Add(Format('%10s', [Subscript]) + ' - ' + Mult1[Subscript])
     //stop when reached the end
 until Subscript = ;

end;


4. Run project and click on the button.

Expected output:


Sorted Property Example


You may have to scroll up and down to see all of the output.

Order Method Example Applies to TMult class

Declaration function Order(const StartSubscript: string; Direction: integer): string;

Description

The Order method works very similar to the $ORDER function in M. Using the Order method you can traverse through the list of elements in the Mult property of an RPC parameter.

The StartSubscript parameter is the subscript of the element whose next or previous sibling will be returned. If the Direction parameter is a positive number, then the subscript of the following element will be returned, while if it’s 0 or negative, then the predecessor’s subscript will be returned. If the list is empty or there are no more elements beyond the StartSubscript parameter, then empty string will be returned. You can use the empty string as a StartSubscript parameter, then, depending on the Direction parameter, you will get the subscript of the first or the last element in the list.

There are some important differences between this method and the $ORDER function in M. Unlike the $ORDER function, the Order method requires both parameters to be passed in. If the StartSubscript parameter is not an empty string, it must be equal to one of the subscripts in the list, otherwise an empty string will be returned. It is case-sensitive. Unlike arrays in M, elements in TMult may or may not be in alphabetical order, depending on the Sorted property, so Order may not return the next or previous subscript in collating sequence.

See RPC Limits for information about the size of parameters and results that can be passed to and returned from the TMult class.

Order Example The following program code demonstrates how to get the next and previous elements in a TMult list:


procedure TForm1.Button1Click(Sender: TObject); var

 Mult: TMult;
 Subscript: string;

begin

 {Create Mult. Make Form1 its owner}
 Mult := TMult.Create(Form1);
 Mult['First'] := 'One';
 {Store element pairs one by one}
 Mult['Second'] := 'Two';
 Mult['Third'] := 'Three';
 Mult['Fourth'] := 'Four';
 {Subscript will be Fourth}
 Subscript := Mult.Order('Third',1);
 {Subscript will be Second}
 Subscript := Mult.Order('Third',-1);
 {Subscript will be . THIRD subscript does not exist}
 Subscript := Mult.Order('THIRD',1);
 {Subscript will be First}
 Subscript := Mult.Order(,1);
 {Subscript will be Fourth}
 Subscript := Mult.Order(,-1);

end;

Position Method Example Applies to TMult class

Declaration function Position(const Subscript: string): longint;

Description

The Position method takes the string subscript of an item in a TMult variable and returns its numeric index position much like a TStringList’s IndexOf method. Because TMult uses a TStringList internally, the IndexOf method is used to implement the Position method. The first position in the TMult is 0. If TMult is empty, or the Subscript does not identify an existing item, Position returns -1.

The Position and Subscript methods are the reciprocals of each other.

See RPC Limits for information about the size of parameters and results that can be passed to and returned from the TMult class.

Position Example The following program code demonstrates how to get the position of an item in a TMult variable:


procedure TForm1.Button1Click(Sender: TObject); var

 Mult: TMult;

begin

 {Create Mult. Make Form1 its owner}
 Mult := TMult.Create(Form1);
 Label1.Caption := 'The position of the Third element is ' +
    {will be -1 since the list is empty}
    IntToStr(Mult.Postion('Third'));
 Mult['Second'] := 'Two';
 Label1.Caption := 'The position of the Third element is ' +
    {will be -1 since 'Third' item does not exit}
    IntToStr(Mult.Postion('Third'));
 Label1.Caption := 'The position of the Second element is ' +
    {will be 0, TMult positions start with 0}
    IntToStr(Mult.Postion('Second'));

end;

Subscript Method Example Applies to TMult class

Declaration function Subscript(const Position: longint): string;

Description

The Subscript method takes the numeric position of an item in a TMult variable and returns its string subscript. If TMult is empty, or the Position is greater than the number of items in the list, an empty string will be returned.

The Subscript and Position methods are the reciprocals of each other.

See RPC Limits for information about the size of parameters and results that can be passed to and returned from the TMult class.

Subscript Example The following program code demonstrates how to get the subscript of an item in a TMult variable:


procedure TForm1.Button1Click(Sender: TObject); var

 Mult: TMult;

begin

 {Create Mult. Make Form1 its owner}
 Mult := TMult.Create(Form1);
 Label1.Caption := 'The subscript of the item at position 1 is ' +
    {will be empty since the list is empty}
    Mult.Subscript(1);
 Mult['Second'] := 'Two';
 Label1.Caption := 'The subscript of the item at position 1 is ' +
    {will be empty. Only one item in list so far at 0th position}
    Mult.Subscript(1);
 Mult['Third'] := 'Three';
 Label1.Caption := 'The subscript of the item at position 1 is ' +
    {will be Third}
    Mult.Subscript(1);

end;

Assign Method Example Applies to TMult class

Declaration procedure Assign(Source: TPersistent);

Description

The Assign method for a TMult class takes either a Tstrings, a TStringList, or another TMult. In the case where the source is a TMult, the owner of the Assign method gets the exact copy of the source with all string subscripts and values. In the case where the source is a Tstrings or a TStringList, the items are copied such that the strings property of each item becomes the Value, while the index becomes the subscript in the string form.

See RPC Limits for information about the size of parameters and results that can be passed to and returned from the TMult class.

Assign Example The following program code demonstrates the use of the TMult assign method to assign listbox items (Tstrings) to a TMult: 1. Start a new application. 2. Drop one listbox, one memo and one button on the form. Arrange controls as in the figure below. 3. Copy the following code to the Button1.OnClick event:


procedure TForm1.Button1Click(Sender: TObject); var

 Mult1: TMult;
 Subscript: string;

begin

 //Create Mult1. Make Form1 its owner
 Mult1 := TMult.Create(Form1);
 //Fill listbox with some strings
 ListBox1.Items.Add('One');
 ListBox1.Items.Add('Two');
 ListBox1.Items.Add('Three');
 ListBox1.Items.Add('Four');
 ListBox1.Items.Add('Five');
 //assign (copy) listbox strings to Mult
 Mult1.Assign(ListBox1.Items);
 //configure memo box for better display
 Memo1.Font.Name := 'Courier';
 Memo1.Lines.Clear;
 Memo1.Lines.Add('Tstrings assigned:');
 //set a starting point
 Subscript := ;
 repeat
   //get next Mult element
   Subscript := Mult1.Order(Subscript, 1);
   //if not the end of list
   if Subscript <>  then
     //display subscript – value
     Memo1.Lines.Add(Format('%10s', [Subscript]) + ' - ' + Mult1[Subscript])
 //stop when reached the end
 until Subscript = ;

end;


4. Run the project and click on the button.

Expected output:


Assign Method Example


The following program code demonstrates the use of the TMult assign method to assign one TMult to another: 1. Start a new application. 2. Drop one memo and one button on the form. Arrange controls as in the figure below. 3. Copy the following code to the Button1.OnClick event:


procedure TForm1.Button1Click(Sender: TObject); var

 Mult1, Mult2: TMult;
 Subscript: string;

begin

 //Create Mult1. Make Form1 its owner
 Mult1 := TMult.Create(Form1);
 //Create Mult2. Make Form1 its owner
 Mult2 := TMult.Create(Form1);
 //Fill Mult1 with some strings
 Mult1['First'] := 'One';
 Mult1['Second'] := 'Two';
 Mult1['Third'] := 'Three';
 Mult1['Fourth'] := 'Four';
 Mult1['Fifth'] := 'Five';
 //assign (copy) Mult1 strings to Mult2
 Mult2.Assign(Mult1);
 //configure memo box for better display
 Memo1.Font.Name := 'Courier';
 Memo1.Lines.Clear;
 Memo1.Lines.Add('TMult assigned:');
 //set a starting point
 Subscript := ;
 repeat
   //get next Mult element
   Subscript := Mult2.Order(Subscript, 1);
   //if not the end of list
   if Subscript <>  then
     //display subscript – value
     Memo1.Lines.Add(Format('%10s', [Subscript]) + ' - ' + Mult2[Subscript])
 //stop when reached the end
 until Subscript = ;

end;


4. Run the project and click on the button.

Expected output:


TMult Assign Method Example

TParams Class Property Method Example Unit TRPCB

Description

The TParams class is used to hold parameters (i.e., array of TParamRecord) used in a remote procedure call (RPC). You don’t need to know in advance how many parameters you’ll need or allocate memory for them; a simple reference or an assignment to a parameter creates it.

The Clear procedure can be used to remove/clear data from TParams. Previously, this procedure was Private, but as of Patch XWB*1.1*13, it was made Public.

TParams Example The following program code demonstrates how a TParams class can be used to save off the TRPCBroker component parameters and restore them later:


procedure TForm1.Button1Click(Sender: TObject); var

 SaveParams: TParams;
 SaveRemoteProcedure: string;

begin

 {create holding variable with Form1 as owner}
 SaveParams := TParams.Create(self);
 {save parameters}
 SaveParams.Assign(brkrRPCBroker1.Param);
 SaveRemoteProcedure := brkrRPCBroker1.RemoteProcedure;
 brkrRPCBroker1.RemoteProcedure := 'SOME OTHER PROCEDURE';
 brkrRPCBroker1.ClearParameters := True;
 brkrRPCBroker1.Call;
 {restore parameters}
 brkrRPCBroker1.Param.Assign(SaveParams);
 brkrRPCBroker1.RemoteProcedure := SaveRemoteProcedure;
 {release memory}
 SaveParams.Free;

end;

TParams Property TParams Count

TParams Method TParams Assign

TParams Count Property Example Applies to TParams class

Declaration property Count: Word;

Description

The Count property contains the number of parameters in a TParams class. If the TParams class is empty, Count will be zero.

TParams Count Example The following program code displays the number of parameters in a TParams variable within the caption of a label when the user clicks the CountParameters button:


procedure TForm1.CountParametersClick(Sender: TObject); begin

 Label1.Caption := 'There are ' + IntToStr(brkrRPCBroker1.Param.Count) +
   ' parameters.';

end;

TParams Assign Method Example Applies to TParams class

Declaration procedure Assign(Source: TParams);

Description

The Assign method for a TParams class takes another TParams class parameter. The Assign method is useful for copying one TParams class to another. The entire contents of the passed in TParams class are copied into the owner of the assign method. The Assign method first deletes all of the parameters in the receiving class and then copies the parameters from the passed in class, creating a whole duplicate copy.

See RPC Limits for information about the size of parameters and results that can be passed to and returned from the TParams class.

TParams Assign Example The following program code demonstrates how a TParams assign method can be used to save off the TRPCBroker component parameters and restore them later:


procedure TForm1.Button1Click(Sender: TObject); var

 SaveParams: TParams;
 SaveRemoteProcedure: string;

begin

 {create holding variable with Form1 as owner}
 SaveParams := TParams.Create(self);
 {save parameters}
 SaveParams.Assign(brkrRPCBroker1.Param);
 SaveRemoteProcedure := brkrRPCBroker1.RemoteProcedure;
 brkrRPCBroker1.RemoteProcedure := 'SOME OTHER PROCEDURE';
 brkrRPCBroker1.ClearParameters := True;
 brkrRPCBroker1.Call;
 {restore parameters}
 brkrRPCBroker1.Param.Assign(SaveParams);
 brkrRPCBroker1.RemoteProcedure := SaveRemoteProcedure;
 {release memory}
 SaveParams.Free;

end;

RPCConf1 Unit Library Methods GetServerInfo GetServerIP


To see a listing of items declared in this unit including their declarations, use the ObjectBrowser.

SplVista Unit Library Methods SplashOpen SplashClose


To see a listing of items declared in this unit including their declarations, use the ObjectBrowser.

MFunStr Unit Library Methods piece translate


To see a listing of items declared in this unit including their declarations, use the ObjectBrowser.

Hash Unit Library Methods Encrypt Decrypt


To see a listing of items declared in this unit including their declarations, use the ObjectBrowser.

TRPCB Unit The TRPCB unit contains the declarations for the TRPCBroker component.

When you add a component declared in this unit to a form, the unit is automatically added to the uses clause of that form's unit.

The following items are automatically declared in the uses clause:

SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs


Component TRPCBroker


Classes TMult TParamRecord TParams TVistaLogin TVistaUser


Types EBrokerError TloginMode TParamType


Library Methods GetAppHandle TMult Class Methods TParams Class Method TRPCBroker Component Methods


To see a listing of items declared in this unit including their declarations, use the ObjectBrowser.

IP Address

The Internet Protocol (IP) address is the network interface address for a client workstation, server, or device.

DNS

The Domain Name Service (DNS) is a distributed database that maps names to their Internet Protocol (IP) addresses or IP addresses to their names. A query to this database is used to resolve names and IP addresses.

HOSTS File

The HOSTS file is an ASCII text file that contains a list of the servers and their Internet Protocol (IP) addresses. We recommend you put in an entry (i.e., "DHCPSERVER") that points to the main server you intend using with the Broker the majority of the time. In your applications you will be able to specify any server you wish, however, if the Server property = " (i.e., null), you will get an error.

$JOB

Contains your operating system job number on the server.

On DSM for OpenVMS systems, this is the process identification (PID) number of your process.

On DSM for DEC OSF/1 systems, the job number is the PID of the child process created when you enter the DSM command.

$ORDER

$ORDER(variable name{,integer code})

Returns the subscript of the previous or next sibling in collating sequence of a specified array node.

To obtain the first subscript of a level, specify a null subscript in the argument.

REMOTE PROCEDURE File

The RPC Broker consists of a single global that stores the REMOTE PROCEDURE file:


File # File Name Global Location 8994 REMOTE PROCEDURE ^XWB(8994,


This is the common file used by all applications to store all remote procedure calls accessed via the Broker. All RPCs used by any site-specific client/server application software using the RPC Broker interface must be registered and stored in this file.

This file is used as a repository of server-based procedures in the context of the Client/Server architecture. By using the Remote Procedure Call (RPC) Broker, applications running on client workstations can invoke (call) the procedures in this file to be executed by the server and the results are returned to the client application.

The RPC subfield (#19.05) of the OPTION File (#19) points to RPC field (#.01) of the REMOTE PROCEDURE file (#8994).

Windows Registry

Applications built with Version 1.1 of the Broker use the Windows Registry to store the available servers and ports accessed via the Broker.

The Windows Registry replaces the [RPCBroker_Servers] section of the VISTA.INI file. The VISTA.INI file is no longer used by applications built with Version 1.1 of the Broker. However, this file continues to be used by applications built using version 1.0 of the Broker (e.g., PCMM). During the installation of the Broker relevant data from the VISTA.INI file is moved to the Windows Registry. Subsequent reads and writes are done via the Registry.

The VISTA.INI file created with Broker V. 1.0 must not be removed from the Windows directory on the client workstation. It is still required for 16-bit Broker-based applications created using version 1.0 of the Broker (e.g., PCMM).

ZDEBUG

A command used to enable or disable debug mode in Digital Standard M (DSM):

>ZDEBUG ON (turns on debugging)

>ZDEBUG OFF (turns off debugging)

XUPROGMODE

A security key distributed by Kernel as part of its Menu Manager. This security key enables access to a number of programmer-oriented options in Kernel.

Accessibility

Run-time only
Read-only

KernelLogIn Property Example Applies to TRPCBroker component

Declaration property KernelLogIn: Boolean;

Description The KernelLogin design-time property is a Boolean property, which indicates the manner of sign-in: · If True, the regular Kernel login security form will be presented. · If False, the Broker will use the TVistaLogin class for signon.


The TVistaLogin class is referenced during Silent Login.

LogIn Property Example Applies to TRPCBroker component

Declaration property LogIn: TVistaLogin;

Description The LogIn property is available at run-time only. It holds parameters that the application needs to pass for Silent Login. The instance of the TVistaLogin used for this property is created automatically during the creation of the TRPCBroker object and is therefore available for reference as a TRPCBroker property without any user setup.

User Property Example Applies to TRPCBroker component

Declaration property User: TVistaUser;

Description The User property is available at run-time only. This instance of the TVistaUser object is created during the Create process for the TRPCBroker instance. The object contains data on the current user and is updated as a part of the user authentication process.

TVistaLogin Class Properties Example Unit TRPCB

Description

The TVistaLogin class is used to hold login parameters for Silent Login.

TVistaLogin Properties TVistaLogin Class Legend AccessCode Division DivList DUZ ErrorText LoginHandle Mode MultiDivision NTToken (not in service) OnFailedLogin PromptDivision VerifyCode

Mode Property Example Applies to TVistaLogin class

Declaration property Mode: TloginMode;

Description The Mode property is available at run-time only. It indicates the mode of Silent Login. The possible values include: lmAVCodes, lmAppHandle, and lmNTToken.

For a demonstration using the lmAVCodes, please run the lmAVCodes_Demo.EXE located in the ..\BDK32\Samples\SilentSignOn directory.

For a demonstration using the lmAppHandle, please run the lmAppHandle_Demo.EXE located in the ..\BDK32\Samples\SilentSignOn directory.

At present, any attempt to use the lmNTToken Silent Login type will result in a failed login.

AccessCode Property Example Applies to TVistaLogin class

Declaration property AccessCode: String;

Description The AccessCode property is available at run-time only. It holds the Access code for the lmAVCodes mode of Silent Login. The user's Access code value should be set in as clear text. It is encrypted before it is transmitted to the server.

For more information on Access codes, please refer to the "Part 1: Signon/Security" section in the Kernel Systems Manual.

For a demonstration using the lmAVCodes, please run the lmAVCodes_Demo.EXE located in the ..\BDK32\Samples\SilentSignOn directory.

VerifyCode Property Example Applies to TVistaLogin class

Declaration property VerifyCode: String;

Description The VerifyCode property is available at run-time only. It holds the Verify code for lmAVCodes mode of Silent Login. Like the AccessCode property, the user's Verify code is also encrypted before it is transmitted to the server.

For more information on Verify codes, please refer to the "Part 1: Signon/Security" section in the Kernel Systems Manual.

For a demonstration using the lmAVCodes, please run the lmAVCodes_Demo.EXE located in the ..\BDK32\Samples\SilentSignOn directory.

LoginHandle Property Applies to TVistaLogin class

Declaration property LoginHandle: String;

Description The LoginHandle property is available at run-time only. It holds the Application Handle for the lmAppHandle mode of Silent Login. The Application Handle is obtained from the server by a currently running application using the GetAppHandle function in the TRPCB unit. The function returns a String value, which is then passed as a command line argument with an application that is being started. The new application must know to look for the handle, and if present, set up the Silent Login. The StartProgSLogin procedure in the RpcSLogin unit can be used directly or as an example of how the application would be started with a valid AppHandle as a command line argument. The CheckCmdLine procedure in the RpcSLogin unit can be used in an application to determine whether an AppHandle has been passed and to initiate the Broker connection or used as an example of how this could be done.

The two procedures referenced here also pass the current Server, ListenerPort, and Division for the user so that the connection would be made to the same server as the original application.

The AppHandle that is obtained via the GetAppHandle function is only valid for approximately 20 seconds, after which the Silent Login would fail.

For a demonstration using the lmAppHandle, please run the lmAppHandle_Demo.EXE located in the ..\BDK32\Samples\SilentSignOn directory.

Division Property Applies to TVistaLogin class

Declaration property Division: String;

Description The Division property is available at run-time only. It can be set to the desired Division for a user for Silent Login.

See Handling Divisions During Silent Login for information about handling multi-divisions during the Silent Login process.

DivList Property (read-only) Applies to TVistaLogin class

Declaration property DivList: Tstrings;

Description The DivList property is available at run-time only. This read-only property is a list of divisions that are available for selection by the user for the signon division. This list is filled in, if appropriate, during the Silent Login at the same time that the user is determined to have multiple divisions from which to select. The first entry in the list is the number of divisions present, followed by the names of the divisions that are available to the user.

See Handling Divisions During Silent Login for information about handling multi-divisions during the Silent Login process.

DUZ Property Applies to TVistaLogin class

Declaration property DUZ: String;

Description The DUZ property is available at run-time only. It holds the user’s Internal Entry Number (IEN) from the NEW PERSON file (#200) for TVistaLogin.

MultiDivision Property Applies to TVistaLogin class

Declaration property MultiDivision: Boolean;

Description The MultiDivision property is available at run-time only. It indicates whether the user has multi-divisional access. It is set during the Silent Login process, if the user has more than one division that can be selected.

See Handling Divisions During Silent Login for information about handling multi-divisions during the Silent Login process.

ErrorText Property Applies to TVistaLogin class

Declaration property ErrorText: String;

Description The ErrorText property is available at run-time only. It holds text of any error message returned by the server during the attempted Silent Login. It should be checked if the login fails. For example, it could indicate the following: · The Verify code needs to be changed. · An invalid Access/Verify code pair. · An invalid Division.

PromptDivision Property Example Applies to TVistaLogin class

Declaration property PromptDivison: Boolean;

Description The PromptDivision property is available at run-time only. It should be set to True, if the user should be prompted for Division during Silent Login. The Prompt will only occur if the user has multi-division access. This property should be set to False, if the Prompt should not be displayed due to the manner in which the application is running. However, if set to False and multi-division access is a possibility, then the application must handle it in another way. For example, the application developer would do the following: 1. Set Login.PromptDivision to False. 2. Set the Connected property to True to signon. 3. On return, check whether the Connected property was set to True or check whether the Login.ErrorText property was non-null (and especially "No Division Selected"). 4. If the connection was successful, there is no problem. Otherwise, proceed to Steps 5 - 8. 5. Check the Login.MultiDivision property and see if it was set to True (which is what would be expected). 6. If the Login.MultiDivision property is set to True, then check the Login.DivList property for a list of the available divisions (remember the first entry is the number of entries that follow) and, in whatever method was available to the application, have the user select the correct division. 7. Set the Login.Division property to the selected Division. 8. Set theConnected property to True, so the connection would be attempted to be established again.

NTToken Property (not in service) Applies to TVistaLogin class

Declaration property NTToken: String;

Description The NTToken property will only be available at run-time. Currently, this property is a placeholder for a special token associated with a different type of Silent Login that is still in development for the lmNTToken mode for Silent Login.

At present, any attempt to use the lmNTToken Silent Login type will result in a failed login.

OnFailedLogin Property Example Applies to TVistaLogin class

Declaration property OnFailedLogin: TOnLoginFailure;

Description The OnFailedLogin property is available at run-time only. It holds a procedure to be invoked on a failed Silent Login that permits an application to handle errors as desired, where TOnLoginFailure is defined as:

TOnLoginFailure = procedure (VistaLogin: TVistaLogin) of object;


For example, an application could define:

Procedure HandleLoginError(Sender: TObject);

and then set:

OnFailedLogin := HandleLoginError;

TVistaUser Class Properties Unit TRPCB

Description

The TVistaUser class is used to hold parameters related to the current user. These parameters are filled in as part of the login procedure.

This class is used as a property by the TRPCBroker class. This property with its associated data is available to all applications, whether or not they are using a Silent Login.

TVistaUser Properties TVistaUser Class legend Division DTime DUZ Language Name ServiceSection StandardName Title VerifyCodeChngd

DUZ Property Applies to TVistaUser class

Declaration property DUZ: String;

Description The DUZ property is available at run-time only. It holds the user's Internal Entry Number (IEN) from the NEW PERSON file (#200) for TVistaUser.

Name Property Applies to TVistaUser class

Declaration property Name: String;

Description The Name property is available at run-time only. It holds the user's name from the NEW PERSON file (#200).

StandardName Property Applies to TVistaUser class

Declaration property StandardName: String;

Description The StandardName property is available at run-time only. It holds the user's standard name from the NEW PERSON file (#200).

Title Property Applies to TVistaUser class

Declaration property Title: String;

Description The Title property is available at run-time only. It holds the user’s title from the NEW PERSON file (#200).

ServiceSection Property Applies to TVistaUser class

Declaration property ServiceSection: String;

Description The ServiceSection property is available at run-time only. It holds the user’s service section from the NEW PERSON file (#200).

Language Property Applies to TVistaUser class

Declaration property Language: String;

Description The Language property is available at run-time only. It holds the user’s language from the NEW PERSON file (#200).

DTime Property Applies to TVistaUser class

Declaration property DTime: String;

Description The DTime property is available at run-time only. It holds the user’s DTime. DTime sets the time a user has to respond to timed read. It can be set from 1 to 99999 seconds.

VerifyCodeChngd Property Applies to TVistaUser class

Declaration property VerifyCodeChngd: Boolean;

Description The VerifyCodeChngd property is available at run-time only. It indicates whether or not the user's Verify code has changed.

Silent Login Example Silent Login is a way to log in a user with known login information. Silent Login skips the step of asking the user for login information. It is similar to Auto Signon in some ways, but there are important differences.


Silent Login Compared to Auto Signon

In Auto Signon, the Client Agent manages the login process on the client. On a primary login (i.e., no existing connections), the user is prompted for Access and Verify codes. On secondary logins, the Client Agent handles the login with the information from the primary login. Developers do not have access to the Auto Signon process.

For more information on Auto Signon, see the "RPC Broker Systems Manual."

Silent Login offers developers an opportunity to skip the login process for the user if they have access to login information from some other source. It is up to the developer to deliver the appropriate login information to the application and enable the Silent Login process.


Interaction Between Silent Login and Auto Signon

On primary login, Silent Login happens if it is enabled (the KernelLogIn property is set to False and the AccessCode, VerifyCode and Mode properties of the LogIn property are set or the AppHandle and Mode properties are set). On secondary logins, the Client Agent, if enabled, handles the login and the Silent Login is bypassed. In other words, if there already is a connection and the Client Agent is enabled, the Silent Login information is not used.

The "XUS SIGNON SETUP" RPC is called before a normal login or a Silent Login and if it identifies the user via Client Agent at the IP address, that identification is used to log the user in.

Silent Login Examples Silent Login Example 1: lmAVCodes

Here is an example of how to use Silent Login by passing the Access and Verify codes to the TVistaLogin class.


brkrRPCBroker1.KernelLogIn := False; brkrRPCBroker1.LogIn.Mode := lmAVCodes; brkrRPCBroker1.LogIn.AccessCode := ********; brkrRPCBroker1.LogIn.VerifyCodeCode := ********; brkrRPCBroker1.LogIn.PromptDivison := True; brkrRPCBroker1.LogIn.OnFailedLogin := myevent; try

   brkrRPCBroker1.Connected := True;

except

 exit

end;


If brkrRPCBroker1.Connected is True, then Silent Login has worked.

For a demonstration using the lmAVCodes, please run the lmAVCodes_Demo.EXE located in the ..\BDK32\Samples\SilentSignOn directory.


Example 2: lmAppHandle

Here is an example of how to use Silent Login by passing an Application Handle to the TVistaLogin class.

The lmAppHandle mode of the Silent Login is used when an application starts up a second application. If the second application tests for arguments on the command line, it is possible for this application to be started and make a connection to the server without user interaction.

An example of a procedure for starting a second application with data on the command line to permit a Silent Login using the LoginHandle provided by the first application is shown below. This is followed by a procedure that can be called in the processing related to FormCreate to use this command line data to initialize the TRPCBroker component for Silent Login. It should be noted that the procedures shown here are included within the RpcSLogin unit, and can be used directly from there. If the value for ConnectedBroker is nil, the application specified in ProgLine will be started and any command line included in ProgLine will be passed to the application.

In the second application, a call to the Broker should be made shortly after starting, since the LoginHandle passed in has a finite lifetime (approximately 20 seconds) during which it is valid for the Silent Login.


procedure StartProgSLogin(const ProgLine: String; ConnectedBroker: TRPCBroker); var

 StartupInfo: TStartupInfo;
 ProcessInfo: TProcessInformation;
 AppHandle: String;
 CmndLine: String;

begin

 FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
 with StartupInfo do
 begin
   cb := SizeOf(TStartupInfo);
   dwFlags := STARTF_USESHOWWINDOW;
   wShowWindow := SW_SHOWNORMAL;
 end;
 CmndLine := ProgLine;
 if ConnectedBroker <> nil then
 begin
   AppHandle := GetAppHandle(ConnectedBroker);
   CmndLine := CmndLine + ' s='+ConnectedBroker.Server + ' p=' 
                        + IntToStr(ConnectedBroker.ListenerPort) + ' h=' 
                        + AppHandle + ' d=' + ConnectedBroker.User.Division;
 end;
 CreateProcess(nil, Pchar(CmndLine), nil, nil, False,
     NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInfo);

end;


{btnStart is clicked to start the second application Test2.exe} procedure TForm1.btnStartClick(Sender: TObject); var

 CurDir: string;

begin

 {Use Test2.exe and expecting it to be in the startup directory for the current application}
 CurDir := ExtractFilePath(ParamStr(0)) + 'Test2.exe';
 {Now start application with Silent Login}
 StartProgSLogin(CurDir, brkrRPCB1);

end;


The following procedure (CheckCmdLine) would be called in the FormCreate code of the application being started to check for command line input, and if relevant to the Broker connection, to set it up.

This code assumes that s=, p=, d=, and h= are used in conjunction with the values for Server, ListenerPort, User.Division, and LoginHandle, respectively.

The command line might look like:

ProgramName.exe s=DHCPSERVER p=9200 d=692 h=~1XM34XYYZZQQ_X


The TRPCB and RpcSLogin units would need to be included in the USES clause.


procedure CheckCmdLine(brkrRPCB: TRPCBroker); var

j: integer;

begin

 // Iterate through possible command line arguments
 for j := 0 to 15 do
 begin
   if ParamStr(j) <>  then
     Form1.Memo1.Lines.Add(IntToStr(j) + '  ' + ParamStr(j));
   if Pos('p=',ParamStr(j)) > 0 then
     brkrRPCB.ListenerPort := StrToInt(Copy(ParamStr(j),
                      (Pos('=',ParamStr(j))+1),length(ParamStr(j))));
   if Pos('s=',ParamStr(j)) > 0 then
     brkrRPCB.Server := Copy(ParamStr(j),
                      (Pos('=',ParamStr(j))+1),length(ParamStr(j)));
   if Pos('h=',ParamStr(j)) > 0 then
   begin
     brkrRPCB.Login.LoginHandle := Copy(ParamStr(j),
                      (Pos('=',ParamStr(j))+1),length(ParamStr(j)));
     if brkrRPCB.Login.LoginHandle <>  then
     begin
       brkrRPCB.KernelLogIn := False;
       brkrRPCB.Login.Mode := lmAppHandle;
     end;
   end;
   if Pos('d=',ParamStr(j)) > 0 then
     brkrRPCB.Login.Division := Copy(ParamStr(j),
                      (Pos('=',ParamStr(j))+1),length(ParamStr(j)));
 // for end
 end;

end;

For a demonstration using the lmAppHandle, please run the lmAppHandle_Demo.EXE located in the ..\BDK32\Samples\SilentSignOn directory.

CurrentContext Property (read-only) Example Applies to TRPCBroker component

Declaration property CurrentContext: String;

Description The CurrentContext property is available at run-time only. This read-only property provides the current context. Developers can save off the current context into a local variable, set a new context, and then restore the original context from the local variable before finishing. This permits the application to use the CreateContext method with an additional context when an initial context has already been established.

TLoginMode Type Used with the Mode property as part of the TVistaLogin class.

Unit TRPCB

type TLoginMode = (lmAVCodes, lmAppHandle, lmNTToken);

Description

The TLoginMode type includes the acceptable values that can be used during Silent Login. If the KernelLogIn property is set to False, then it will be a Silent Login. Thus, one of these mode types has to be set in the TVistaLogin class Mode property. The Broker will use the information to perform a Silent Login.

The following table lists the possible values:


Value Meaning lmAVCodes Used if the application is passing in the user's Access and Verify codes during Silent Login.

For a demonstration using the lmAVCodes, please run the lmAVCodes_Demo.EXE located in the ..\BDK32\Samples\SilentSignOn directory. lmAppHandle Used to pass in an application handle rather than a user's Access and Verify codes during Silent Login. It sets the mode to lmAppHandle and the KernelLogIn property to false. Indicates that an application handle is being passed to the application when it was being started as opposed to Access and Verify codes.

For a demonstration using the lmAppHandle, please run the lmAppHandle_Demo.EXE located in the ..\BDK32\Samples\SilentSignOn directory. lmNTToken Set when the login is being handled as an Enterprise Single Sign-on (ESSO).

At present, any attempt to use the lmNTToken Silent Login type will result in a failed login.

Division Property Applies to TVistaUser class

Declaration property Division: String;

Description The Division property is available at run-time only. It is set to the division for a user when they are logged on.

Handling Divisions During Silent Login A login may be successful, but if the user has multiple divisions from which to choose and fails to select one, the connection is terminated and a failed login message is generated. This becomes a potential problem in that a Silent Login may have problems, if the user has multiple divisions from which to choose and the PromptDivision property is not set to True.

If the application wishes to handle the user specification of the division, it may attempt to set the TRPCBroker component Connected property to True. If upon return, the Connected property is still False, it can check the Login.MultiDivision property. If the MultiDivision property is True, the user has multiple divisions from which to choose. The application will find the possible values for selection in the Login.DivList property (i.e., Tstrings). The values that are present in the DivList property will be similar to the following example:

3 1^SAN FRANCISCO^66235 2^NEW YORK^630 3^SAN DIEGO^664^1

The first (index = 0) entry is the total number of divisions that can be selected (e.g., 3 in this example). This is followed by the different divisions comprised of the following pieces: · The second ^-piece of each entry is the name. · The third ^-piece of each entry is the number associated with the division. · The fourth ^-piece with the value of 1, if present in one of the entries, is the default division for the user.

The safest value to set as the Login.Division property might be the third ^-piece of the selected division.

If the desired division is known ahead of time, it can be set into the Login.Division property for the TRPCBroker component prior to attempting the connection.

Socket Property Example Applies to TRPCBroker component

Declaration property Socket: Integer;

Description The Socket property is available at run-time only. It contains the active port being used for the TCP/IP connection to the server. This is the port that is currently in use on the server as opposed to the ListenerPort that was used to make the initial connection. After the initial connection, the server connection is moved to another port number (i.e., Socket), which is used for the remainder of the session.

Socket Example The following program code populates the Socket property with the active port on the server:


function ExistingSocket(Broker: TRPCBroker): integer; var

 Index: integer;

begin

 Result := 0;
 if Assigned(BrokerConnections) and
    BrokerConnections.Find(Broker.Server + ':' + IntToStr(Broker.ListenerPort), Index) then
   Result := TRPCBroker(BrokerConnections.Objects[Index]).Socket;

end;

ShowErrorMsgs Property Applies to TRPCBroker component

Declaration property ShowErrorMsgs: TShowErrorMsgs;

Description The ShowErrorMsgs design-time property gives the developer the ability to determine how an exception will be handled, if an error handler has not been provided through the OnRpcbError property (i.e., a procedure property that is set to the name of a procedure that will be called if an error is encountered). If the OnRpcbError property is assigned, then exception processing will be delegated to that procedure. Otherwise, exception handling will be based on the value of ShowErrorMsgs property.

The following table lists the possible values:

Value Meaning semRaise (default) This is the default value. The Broker will not handle the error directly but pass it off to the application in general to process, which may result in a different message box display or some other type of error indication. semQuiet The error will not be displayed or raised. This requires the application to check the value of the RpcbError property following calls to the Broker to determine whether an error has occurred, and if so, what the error was. This may be desirable, if the application requires that errors not result in display boxes, etc., as might be the case with an NT service or web application.

Run the "Error Handling Demo" application (i.e., XWBOnFail.EXE, located in the ..\BDK\Samples\SilentSignOn p [13] directory), to illustrate the effects of TRPCBroker properties related to Error Handling.

OnRPCBFailure Property Example Applies to TRPCBroker component

Declaration property OnRPCBFailure: TOnRPCBFailure;

Description The OnRPCBFailure property is available at run-time only. It holds a procedure to be invoked when the Broker generates an exception that permits an application to handle errors as desired, where TOnRPCBFailure is defined as:

TOnRPCBFailure = procedure (RPCBroker: TRPCBroker) of object;

The text associated with the error causing the exception will be found in the RPCBError property.

If OnFailedLogin is also set, it will handle any login errors and not pass them up.

Run the "Error Handling Demo" application (i.e., XWBOnFail.EXE, located in the ..\BDK\Samples\SilentSignOn p [13] directory), to illustrate the effects of TRPCBroker properties related to Error Handling.

RPCBError Property (read-only) Applies to TRPCBroker component

Declaration property RPCBError: String;

Description The RPCBError property is available at run-time only. This read-only property contains the Message property associated with the exception or error that was encountered by the instance of the TRPCBroker component.

pchCall Method function pchCall: Pchar;

The pchCall function is the lowest level call used by the TRPCBroker component and each of the other Call methods (i.e., Call, strCall, and lstCall), which are implemented via pchCall. The return value is a Pchar, which can contain anything from a null string, a single text string, or many strings each separated by Return and/or LineFeed characters. For converting multiple lines within the return value into a Tstrings, use the SetText method of the Tstrings.

CurrentContext Example The following program code demonstrates the use of the CurrentContext property in a hypothetical example of saving and restoring the current context of an application:


procedure TForm1.MyFantasticModule; var

 OldContext: String;

begin

 OldContext := RPCB.CurrentContext;  // save off old context
 try
   RPCB.SetContext('MyContext');
   .
   .
   .
 finally
   RPCB.SetContext(OldContext);  // restore context before leaving
 end;

end;

OnRPCBFailure Example For example, an application could define:


Procedure HandleBrokerError(Sender: TObject);

and then set:

OnRPCBFailure := HandleBrokerError;

The initialization of the OnRPCBFailure property should be before the first call to the TRPCBroker component.


The following instance of an error handler will take the Message property of the exception and store it with a time date stamp into a file named Error.Log in the same directory with the application exe:


procedure TForm1.HandleBrokerError(Sender: TObject); var

 ErrorText: String;
 Path: String;
 StrLoc: TStringList;
 NowVal: TDateTime;

begin

 NowVal := Now;
 ErrorText := TRPCBroker(Sender).RPCBError;
 StrLoc := TStringList.Create;
 try
   Path := ExtractFilePath(Application.ExeName);
   Path := Path + 'Error.Log';
   if FileExists(Path) then
     StrLoc.LoadFromFile(Path);
   StrLoc.Add(FormatDateTime('mm/dd/yyyy hh:mm:ss  ',NowVal) + ErrorText);
   StrLoc.SaveToFile(Path);
 finally
   StrLoc.Free;
 end;

end;

TXWBRichEdit Component

Property Parent Class TXWBRichEdit = class(TComponent)

Unit XwbRich20

Description

The TXWBRichEdit component replaces the Introductory Text Memo component on the Login Form. TXWBRichEdit (XwbRich20.pas) is a version of the TRichEdit component that uses Version 2 of Microsoft's RichEdit Control and adds the ability to detect and respond to a Uniform Resource Locator (URL) in the text. This component permits us to provide some requested functionality on the login form. As an XWB namespaced component we are required to put it on the Kernel tab of the component palette, however, it rightly belongs on the Win32 tab.

Properties inherited from the parent component (i.e., TComponent) are not discussed in this Help file (only those properties added to the parent component are described). For help on inherited properties, please see Delphi's documentation on the parent component (i.e., TComponent).

TXWBRichEdit Property TXWBRichEdit URLDetect

URLDetect Property Applies to TXWBRichEdit component

Declaration property URLDetect: Boolean;

Description

The URLDetect design-time property is used to create active ("live") links in an application. If this property is set to True, URLs (http:, mailto:, file:, etc.) are shown in blue and underlined. If the user clicks on the URL, it will open the URL in the appropriate application. If the property is False (the default), URLs appear as normal text and are not active.

TVCEdit Unit The RPC Broker calls the TVCEdit unit at logon when users must change their Verify code (i.e., Verify code has expired). There is also a checkbox on the Signon form that allows uses to change their Verify code at any time.

Library Methods ChangeVerify SilentChangeVerify


To see a listing of items declared in this unit including their declarations, use the ObjectBrowser.

RpcSLogin Unit Library Methods CheckCmdLine StartProgSLogin


To see a listing of items declared in this unit including their declarations, use the ObjectBrowser.

LoginFrm Unit With Patch XWB*1.1*13, a "Change VC" checkbox was added to the to the login form. The user can use this checkbox to indicate that she/he wants to change their Verify code. If this box has been checked, after the user has completed logging in to the system, the Change Verify code dialog will be displayed.

To see a listing of items declared in this unit including their declarations, use the ObjectBrowser.


RPC Overview A Remote Procedure Call (RPC) is a defined call to M code that runs on an M server. A client application, through the RPC Broker, can make a call to the M server and execute an RPC on the M server. This is the mechanism through which a client application can: · Send data to an M server · Execute code on an M server · Retrieve data from an M server


An RPC can take optional parameters to do some task and then return either a single value or an array to the client application. RPCs are stored in the REMOTE PROCEDURE file (#8994).

The following topics are covered: What makes a good RPC? Creating RPCs Using an Existing M API · M Entry Point for an RPC Relationship Between an M Entry Point and an RPC M Entry Point First Input Parameter M Entry Point Return Value Types M Entry Point Input Parameters M Entry Point Examples · RPC Entry in Remote Procedure File RPC Entry in Remote Procedure File RPC Version in Remote Procedure File Blocking an RPC in Remote Procedure File Cleanup after RPC Execution Documenting RPCs · Executing RPCs from Clients How to Execute an RPC from a Client RPC Security: How to Register an RPC RPC Limits Online Code Samples for RPCs

What Makes a Good RPC? The following characteristics help to make a good remote procedure call (RPC): · Silent calls (no I/O to terminal or screen, no user intervention required) · Minimal resources required (passes data in brief, controlled increments) · Discrete calls (requiring as little information as possible from the process environment) · Generic as possible (different parts of the same package as well as other packages could use the same RPC)

Creating RPCs You can create your own custom RPCs to perform Actions on the M server and to retrieve data from the M server. Then you can call these RPCs from your client application. Creating an RPC requires you to perform the following two steps: · Write and test the M entry point that will be called by the RPC. · Add the RPC entry that invokes the M entry point, in the REMOTE PROCEDURE file (#8994).

Relationship Between an M Entry Point and an RPC An RPC can be thought of as a wrapper placed around an M entry point for use with client applications. Each RPC invokes a single M entry point.

An M entry point has defined input and output values/parameters that are passed via the standard M invoking methods. An RPC, however, needs to do the following: · Accept input from the Broker (i.e., passing data/parameters from the client application) · Pass data to the M entry point in a specified manner · Receive values back from the M code in a pre-determined format · Pass M code output back through the Broker to the client application

You can use the $$BROKER^XWBLIB function in M code to determine whether the code is being run in an environment where it was invoked by the Broker. This may help you use M code simultaneously for Broker and non-Broker applications.

You can use RPCVersion to support multiple versions of an RPC. RPCVersion example shows how to do this on the client and server sides.

First Input Parameter (Required) The RPC Broker always passes a variable by reference in the first input parameter to your M routine. It expects results (one of five return value types) to be returned in this parameter. You must always set some return value into that first parameter before your routine returns.

Return Value Types There are five RETURN VALUE TYPES for RPCs as shown in the table below. You should choose a return value type that is appropriate to the type of data your RPC needs to return. For example, to return the DUZ, a return value type of SINGLE VALUE would be appropriate.

The RETURN VALUE TYPE you choose then determines what value(s) you should set into the return value parameter of your M entry point.

You should always set some value into the return value parameter of the M entry point, even if your RPC encounters an error condition.

The following RPC settings, combined with your M entry point, determine how data is returned to your client application:



RPC Return Value Type


How M Entry Point Should Set the Return Parameter RPC Word Wrap On Setting Value(s) returned in Client Results Single Value Set the return parameter to a single value. For example, TAG(RESULT) ;

S RESULT="DOE, JOHN"
Q

No effect Value of parameter, in Results[0]. Array Set an array of strings into the return parameter, each subscripted one level descendant. For example,

TAG(RESULT) ;

S RESULT(1)="ONE"
S RESULT(2)="TWO"
Q 

If your array is large, consider using the GLOBAL ARRAY return value type, to avoid memory allocation errors. No effect Array values, each in a Results item. Word Processing Set the return parameter the same as you set it for the ARRAY type. The only difference is that the WORD WRAP ON setting affects the WORD PROCESSING return value type. True


False Array values, each in a Results item. Array values, all concatenated into Results[0]. Global Array Set the return parameter to a closed global reference in ^TMP. The global's data nodes will be traversed using $QUERY, and all data values on global nodes descendant from the global reference are returned. This type is especially useful for returning data from VA FileMan word processing fields, where each line is on a 0-subscripted node.

The global reference you pass is killed by the Broker at the end of RPC Execution as part of RPC cleanup. Do not pass a global reference that is not in ^TMP or that should not be killed.

This type is useful for returning large amounts of data to the client, where using the ARRAY type can exceed the symbol table limit and crash your RPC. For example, to return signon introductory text you could do:

TAG(RESULT);

M ^TMP("A6A",$J)=

^XTV(8989.3,1,"INTRO")

;this node not needed
K ^TMP("A6A",$J,0)
S RESULT=$NA(^TMP("A6A",$J))
Q

True


False Array values, each in a Results item. Array values, all concatenated into Results[0]. Global Instance Set the return parameter to a closed global reference. For example the following code returns the whole 0th node from the NEW PERSON file for the current user: TAG(RESULT) ;

S RESULT=$NA(^VA(200,DUZ,

0))

Q 

No effect Value of global node, in Results[0].

In the M code called by an RPC, you can use the $$RTRNFMT^XWBLIB function to change the return value type of an RPC on the fly.

Input Parameters (Optional) The M entry point for an RPC can optionally have input parameters (i.e., beyond the first parameter, which is always used to return an output value in). The client passes data to your M entry point through these parameters.

The client can send data to an RPC (and therefore your entry point) in one of the following three Param types:


Param PType Param Value literal Delphi string value, passed as a string literal to the M server. reference Delphi string value, treated on the M Server as an M variable name and resolved from the symbol table at the time the RPC executes. list A single-dimensional array of strings in the Mult property of the Param property, passed to the M Server where it is placed in an array. String subscripting can be used.


The type of the input parameters passed in the Param property of the TRPCBroker component determines the format of the data you must be prepared to receive in your M entry point.

Examples The following two examples illustrate sample M code that could be used in simple RPCs.

1. This example takes two numbers and returns their sum:

SUM(RESULT,A,B) ;add two numbers

S RESULT=A+B
Q

2. This example receives an array of numbers and returns them as a sorted array to the client:

SORT(RESULT,UNSORTED) ;sort numbers

N I
S I=""
F  S I=$O(UNSORTED(I)) Q:I=""  S RESULT(UNSORTED(I))=UNSORTED(I)
Q

RPC Entry in the Remote Procedure File After the M code is complete, you need to add the RPC to the REMOTE PROCEDURE file (#8994). The following fields in the REMOTE PROCEDURE file (#8994) are key to the correct operation of an RPC:


Field Name Required? Description NAME (#.01) Yes The name that identifies the RPC (this entry should be namespaced in the package namespace). TAG (#.02) Yes The tag at which the remote procedure call begins. ROUTINE (#.03) Yes The name of the routine that should be invoked to start the RPC. WORD WRAP ON (#.08) No Affects GLOBAL ARRAY and WORD PROCESSING return value types only. If set to False, all data values are returned in a single concatenated string in Results[0]. If set to True, each array node on the M side is returned as a distinct array item in Results. RETURN VALUE TYPE (#.04) Yes This can be one of five types: SINGLE VALUE, ARRAY, WORD PROCESSING, GLOBAL ARRAY, GLOBAL INSTANCE. This setting controls how the Broker processes an RPC's return parameter.

Cleanup after RPC Execution? The Broker uses XUTL^XUSCLEAN to clean up globals upon application termination.

In addition, there is an RPC return value type, GLOBAL ARRAY, where the application RPC returns a closed form global reference, for example:

^TMP("EKG",220333551)

The Broker kills the data for the global reference for this type of RPC at the end of RPC execution.

Documenting RPCs Each individual application development team is responsible for identifying and providing documentation for all object components, classes, and remote procedure calls they create. Other developers using these components will need to know what RPCs are called because they will need to register them with their applications.

RPCs should be documented in the DESCRIPTION field (#1) in the REMOTE PROCEDURE file (#8994) for those RPCs installed on your system. This gives you the capability of generating a catalog of RPCs from File #8994.


Delphi Component Library and Sample RPCs

The VISTA Data Systems & Integration (VDSI) unit of VISTA System Design & Development (SD&D) will make available a corporate library of object components, classes, and remote procedure calls that are in use and available to the development community at large. The essential benefit of this library is the promotion of object re-use, thereby enhancing development productivity, application consistency, and quality assurance. Therefore, it will contain a wide variety of components, classes, and RPCs from many packages.

The immediate intent is to classify and catalog all of the object classes in use (including the standard Delphi classes), and to make the catalog available to all interested parties via the VISTA System Design & Development (SD&D) Home Page: http://vista.med.va.gov/index.asp

How to Execute an RPC from a Client 1. If your RPC has any input parameters beyond the mandatory first parameter, set a Param node in the TRPCBroker's Param property for each. For each input parameter, set the following subproperties: · Value · PType (literal, list, or reference).


If the parameter's PType is list, however, instead of specifying a value, instead set a list of values in the Mult property.

Here is an example of some settings of the Param property:

brkrRPCBroker1.Param[0].Value := '10/31/97'; brkrRPCBroker1.Param[0].PType := literal; brkrRPCBroker1.Param[1].Mult['"NAME"'] := 'SMITH, JOHN'; brkrRPCBroker1.Param[1].Mult['"SSN"'] := '123-45-6789'; brkrRPCBroker1.Param[1].PType := list;

2. Set the TRPCBroker's RemoteProcedure property to the name of the RPC to execute.

brkrRPCBroker1.RemoteProcedure:='A6A LIST';

3. Invoke the Call method of the TRPCBroker component to execute the RPC. All calls to the Call method should be done within an exception handler try...except statement, so that all communication errors (which trigger the EBrokerError exception) can be trapped and handled. For example:

try

   brkrRPCBroker1.Call;

except

 On EBrokerError do
   ShowMessage('A problem was encountered communicating with the server.');

end;

4. Any results returned by your RPC are returned in the TRPCBroker component's Results property. Depending on how you set up your RPC, results are returned either in a single node of the Results property (Results[0]), or in multiple nodes of the Results property.

You can also use the lstCall and strCall methods to execute an RPC. The main difference between these methods and the Call method is that lstCall and strCall do not use the Results property, instead returning results into a location you specify.

RPC Security: How to Register an RPC Security for RPCs is handled through the RPC registration process. Each client application must create a context for itself, which checks if the application user has access to a "B"-type option in the Kernel menu system. Only RPCs assigned to that option can be run by the client application.

To enable your application to create a context for itself:

1. Create a "B"-type option in the OPTION file (#19) for your application.

The OPTION TYPE "B" represents a Broker client/server type option.

2. In the RPC multiple for this option type, add an entry for each RPC that your application calls. The following fields can be set up for each RPC in your option:


Field Name Entry Description RPC (#.01) Required This field is used to enter a pointer to the REMOTE PROCEDURE file (#8994). This field links the remote procedure call in the REMOTE PROCEDURE file (#8994) to the package option. RPCKEY (#1) Optional This field is used to restrict the use of a remote procedure call to a particular package option. The RPCKEY field is a free-text pointer to the SECURITY KEY file (#19.1). RULES (#2) Optional This field is used to enter M code that is executed when an RPC request is made to verify whether the request should be honored.


3. When you export your package using KIDS, export both your RPCs and your package option. KIDS will automatically associate the RPCs with the package option.

4. Your application must create a context for itself on the server, which checks access to RPCs. In the initial code of your client application, make a call to the CreateContext method of your TRPCBroker component. Pass your application's "B"-type option's name as a parameter. For example:

if not brkrRPCBroker1.CreateContext(option_name) then

 Application.Terminate;

If the CreateContext method returns True, only those RPCs designated in the RPC multiple of your application option will be permitted to run.

If the CreateContext method returns False, you should terminate your application (if you don't your application will run, but you will get errors every time you try to access an RPC).

5. End-users of your application must have the "B"-type option assigned to them on one of their menus, in order for CreateContext to return True. This allows system managers to control access to client applications.

Bypassing RPC Security for Development Having the XUPROGMODE security key allows you to bypass the Broker security checks. You can run any RPC without regard to application context (without having to use the CreateContext method). This is a convenience for when you are developing an application. When you complete development, make sure you test your application from an account without the XUPROGMODE key, to ensure that all RPCs needed are properly registered.

RPC Limits The following is a list of various constants, maximum, and minimum parameters associated with the use of the RPC Broker: · Maximum number of parameters that can be passed to the M server · Maximum size of array that can be passed to the M server · Maximum size of data that can be received in the Windows application from the M server · RPC Time limit

Maximum Number of Parameters

The remote procedure calls (RPCs) become M DO procedures on the M server. Since RPCs are communicated to the M server through a message mechanism, additional information is included with the message.

Parameters are processed as PASCAL short strings with a maximum of 255 characters. Each parameter is encoded with a three-character length plus a type character. Therefore, every parameter occupies length (parameter) + four. The maximum transmission at this time is 240 characters since additional header information is present with every RPC.

A theoretical maximum, where every parameter was length 1 would give number of parameters = 240/5 or 48 parameters. A single parameter (e.g., a long string) could not exceed 240 – 4, or 236 characters. Future support will be based on the PASCAL 32-bit string, which can, theoretically, reach 2 GB. Limitations on the M server will still limit this to far less, however.

Maximum Size of Array

Although approximately only 240 characters can be sent to the M server as call parameters, a single array parameter can be passed in with greater capacity. The RPC can carry both literal and array parameters except that literal parameters are placed first and the single array last in order. Arrays are instantiated at the M server and are stored in a local array format. The maximum size will be dependent on the symbol space available to the M server process. The index size and the value size are subject to limitations as follows: Index and value each cannot exceed 255 – 3, or 252 characters approximately for each individual array elements.

At the time of this writing, 30 to 40 K arrays have easily been passed to the M server in a single RPC call.

Maximum Size of Data

The M server can transmit very large buffers of data back to the Windows client. The Windows client receives the returned data from an RPC into a 32-bit PASCAL string. RPCs can be written on the M server so that they store their results in an M GLOBAL structure, which can span RAM and disk storage media. This GLOBAL storage could be quite large depending on the assigned system quotas to the M server process. The return of the RPC can deliver this quantity to the Windows client. The actual limit will depend on the capacity the Windows operating system will allow the client to process. Tests on a 32-megabyte RAM system have allowed buffers of several megabytes of data to be transmitted from the M server to the Windows client.

Time Limits

A public read/write property (i.e., RPCTimeLimit) allows the application to change the network operation timeout prior to a call. This may be useful during times when it is known that a certain RPC, by its nature, can take a significant amount of time to execute. The value of this property is an integer that cannot be less than 30 seconds nor greater that 32767 seconds. Care should be taken when altering this value, since the network operation will block the application until the operation finishes or the timeout is triggered.

There is also a Server time limit when for how long to stay connected when the client doesn't respond.

RPC Broker Example (32-Bit) The RPC Broker Example sample application provided with the BDK (i.e., BrokerExample.EXE, located in the ..\BDK32\Samples\BrokerEx directory) demonstrates the basic features of developing RPCBroker applications, including: · Connecting to an M server · Creating an application context · Using the GetServerInfo function · Displaying the VISTA splash screen · Setting the TRPCBroker.Param property for each Param PType (literal, reference, list) · Calling RPCs with the Call method · Calling RPCs with the lstCall and strCall methods

The client source code files for the BrokerExample application are located in the ..\BDK32\Samples\BrokerEx directory.

Initially, use Delphi to compile the BrokerExample.DPR into an executable.

Using an Existing M API In some cases an existing M API will provide a useful M entry point for an RPC. As with any M entry point, you will need to add the RPC entry that invokes the M entry point, in the REMOTE PROCEDURE file (#8994).

See also: Relationship Between M Entry Point and RPC

Blocking an RPC in the Remote Procedure File The INACTIVE field of the Remote Procedure File allows blocking of RPCs. The blocking can apply to local access (users directly logged into the site) or remote access (users logged on to a different site) or both. The field can be set either by a package developer and exported by KIDS or by a site manager using VA FileMan.


Value in INACTIVE field 1 = completely unusable 2 = unusable locally 3 = unusable remotely

RPC Version in the Remote Procedure File The VERSION field of the Remote Procedure File indicates the version number of an RPC installed at a site. The field can be set either by a package developer and exported by KIDS or by a site manager using FileMan.

Applications can use XWB IS RPC AVAILABLE or XWB ARE RPCS AVAILABLE to check the availability of a version of an RPC on a server. This is especially useful for RPCs run remotely, as the remote server may not have the latest RPC installed.

Other RPC Broker APIs The Broker Development Kit (BDK) provides the following development APIs in addition to the TRPCBroker component: GetServerInfo Function VISTA Splash Screen Procedures XWB GET VARIABLE VALUE RPC M Emulation Functions Encryption Functions XWB IS RPC AVAILABLE XWB ARE RPCS AVAILABLE Running RPCs on a Remote Server Deferred RPCs


The RPC Broker package provides the following entry points on the server for use in RPC code: $$BROKER^XWBLIB (Determine if running from a Broker call) $$RTRNFMT^XWBLIB (Change return format of RPC)

GetServerInfo Function Example The GetServerInfo function retrieves the end-user's selection of server and port to which to connect. Use this function to set a TRPCBroker component's Server and ListenerPort properties to reflect the end-user's choice before connecting to the server.

If there is more than one server/port to choose from, GetServerInfo displays an application window that allows users to select a service to connect to:



Syntax:

function GetServerInfo(var Server, Port: string): integer;

The unit is RpcConf1.


The GetServerInfo function handles the following scenarios: · If there are no values for server and port in the Windows Registry, GetServerInfo does not display its dialog window, and the automatic default values returned are BROKERSERVER/9200. GetServerInfo returns mrOK. · If exactly one server and port entry is defined in the Windows Registry, GetServerInfo does not display its dialog window. The values in the single Windows Registry entry are returned to the calling application, with no user interaction. GetServerInfo returns mrOK. · If more than one server and port entry exists in the Windows Registry, the dialog window is displayed. The only time that passed in server and port values will be returned to the calling application is if the user presses Cancel. However, if a user selects an entry and clicks on the OK button, the server and port parameters will be changed and returned to the calling application. GetServerInfo returns mrOK if the user pressed the OK button, or mrCancel if the user pressed the Cancel button.

For a demonstration using the Broker and GetServerInfo function, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.

GetServerInfo Example procedure TForm1.btnConnectClick(Sender: TObject); var

 strServer, strPort: string;

begin

 if GetServerInfo(strServer, strPort)<> mrCancel then begin {getsvrinfo begin}
   brkrRPCBroker1.Server := strServer;
   brkrRPCBroker1.ListenerPort := StrToInt(strPort);
   brkrRPCBroker1.Connected := True;
 {getsvrinfo end}
 end;

end;

For a demonstration using the Broker and GetServerInfo function, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.

VISTA Splash Screen Procedures Example Two procedures in SplVista.PAS unit are provided to display a VISTA splash screen when an application loads: procedure SplashOpen; procedure SplashClose(TimeOut: longint);


It is recommended that the VISTA splash screen be opened and closed in the section of Pascal code in an application's project file (i.e., .DPR).


To use the VISTA splash screen in an application: 1. Open your application's project (.DPR) file (in Delphi, choose View | Project Source). 2. Include the SplVista in the uses clause of the project source. 3. Call SplashOpen immediately after the first form of your application is created and call SplashClose just prior to invoking the Application.Run method. 4. Use the TimeOut parameter to ensure a minimum display time. The TimeOut parameter is the minimum number of milliseconds the screen will be shown.


The VISTA splash screen is illustrated below:



For a demonstration using the VISTA Splash Screen, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.

VISTA Splash Screen Example uses

 Forms, Unit1 in 'Unit1.pas', SplVista;

{$R *.RES}

begin

 Application.Initialize;
 Application.CreateForm(TForm1, Form1);
 SplashOpen;
 SplashClose(2000);
 Application.Run;

end.

For a demonstration using the VISTA Splash Screen, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.

XWB GET VARIABLE VALUE RPC Example You can call the XWB GET VARIABLE VALUE RPC (distributed with the RPC Broker) to retrieve the value of any M variable in the server environment. Pass the variable name in Param[0].Value, and the type (reference) in Param[0].PType. Also, the current context of your user must give them permission to execute the XWB GET VARIABLE VALUE RPC (it must be included in the RPC multiple of the "B"-type option registered with the CreateContext function).

XWB GET VARIABLE VALUE Example brkrRPCBroker1.RemoteProcedure := 'XWB GET VARIABLE VALUE'; brkrRPCBroker1.Param[0].Value :='DUZ'; brkrRPCBroker1.Param[0].PType := reference; try

   brkrRPCBroker1.Call;

except

 On EBrokerError do
   ShowMessage('Connection to server could not be established!');

end; ShowMessage('DUZ is '+brkrRPCBroker1.Results[0]);

M Emulation Functions Examples Piece Function

The Piece function is a scaled down Pascal version of M's $PIECE function. It is declared in MFUNSTR.PAS.

function Piece(x: string; del: string; piece: integer) : string;


Translate Function

The Translate function is a scaled down Pascal version of M's $TRANSLATE function. It is declared in MFUNSTR.PAS.

function Translate(passedString, identifier, associator: string): string;

M Emulation Examples Piece Function

Piece3Str:=piece('123^456^789','^',3);


Translate Function

hiStr:=translate('HI','ABCDEFGHI','abcdefghi');

Encryption Functions Kernel and the RPC Broker provide encryptions functions that can be used to encrypt messages sent between the client and the server.


In Delphi

Include HASH in the "uses" clause of the unit in which you'll be encrypting or decrypting.

Function prototypes are as follows: function Decrypt(EncryptedText: string): string; function Encrypt(NormalText: string): string;


On the M Server

To encrypt:

KRN,KDE>S CIPHER=$$ENCRYP^XUSRB1("Hello world!") W CIPHER /U'llTG~TVl&f-


To decrypt:

KRN,KDE>S PLAIN=$$DECRYP^XUSRB1(CIPHER) W PLAIN Hello world!


These encryption functions can be used for any communication between the client and the server where encryption is desired.

$$BROKER^XWBLIB Use this function in the M code called by an RPC to determine if the current process is being executed by the RPC Broker.

Format

$$BROKER^XWBLIB

Input

(none)

Output

Return Value 1 if the current process is being executed by the Broker; 0 if not.

Example

I $$BROKER^XWBLIB D .; broker-specific code

$$RTRNFMT^XWBLIB Use this function in the M code called by an RPC to change the return value type that the RPC will return on the fly.

Format

$$RTRNFMT^XWBLIB(type, wrap)

Input

type Set this to the RETURN VALUE TYPE to change the RPC's setting to. You can set it to one of the following numeric or free text values: numeric free text 1 SINGLE VALUE 2 ARRAY 3 WORD PROCESSING 4 GLOBAL ARRAY 5 FOR GLOBAL INSTANCE

wrap Set to 1 to set the RPC's WORD WRAP ON setting to True; set to 0 to set the RPC's WORD WRAP ON setting to False.

Output Return Value 0 if the return value type could not be changed; otherwise, the numeric code representing the return value type that the RPC is changed to.

Example

I '$$RTRNFMT^XWBLIB("ARRAY",1) D .; branch to code if can't change RPC type

XWB IS RPC AVAILABLE Example Checking RPC Availability on a Remote Server

Use this RPC to determine if a particular RPC is available on a server. The RPC PARAMETER passes the name of the RPC to be checked. The RUN CONTEXT PARAMETER allows you to test availability to a local or a remote user. The VERSION NUMBER PARAMETER allows you to check for a minimum version of an RPC on a remote server.

RETURN VALUE: Boolean 1 = RPC Available 0 = RPC Not Available

RPC PARAMETER: Pass the name of the RPC to be tested in Param[0].Value, and the type (literal) in Param[0].PType.

RUN CONTEXT PARAMETER (Optional): Pass the run context (local or remote) of the RPC in Param[1].Value, and the type (literal) in Param[1].PType. Possible values are: · L = Check if available to be run locally (by a user logged into the server) · R = Check if available to be run remotely (by a user logged in a different server)

If this parameter is not sent, the RPC is checked for both local and remote and both run contexts must be available for the return to be ‘1’ (RPC Available). The check is done against the INACTIVE field in the REMOTE PROCEDURE file .

VERSION NUMBER PARAMETER (Optional): Pass the minimum acceptable version number of the RPC in Param[2].Value, and the type (literal) in Param[2].PType. This parameter is only used if the RUN CONTEXT parameter = “R”. If a numeric value is in this parameter, it will be checked against the value in the VERSION field of the REMOTE PROCEDURE file. If the version number passed is less than or equal to the number in the VERSION field, the RPC will be marked available.

If the VERSION field is null, the check will fail for a numeric value in this parameter.

Also, the current context of your user must give them permission to execute the XWB IS RPC AVAILABLE (it must be included in the RPC multiple of the "B"-type option registered with the CreateContext function).

XWB IS RPC AVAILABLE Example brkrRPCBroker1.RemoteProcedure := 'XWB IS RPC AVAILABLE'; brkrRPCBroker1.Param[0].Value :='XWB GET VARIABLE VALUE'; brkrRPCBroker1.Param[0].PType := literal; brkrRPCBroker1.Param[1].Value := 'R'; brkrRPCBroker1.Param[1].PType := literal;

 {no version number passed in this example as XWB GET VARIABLE VALUE has only one version}

try

   brkrRPCBroker1.Call;

except

 On EBrokerError do
   ShowMessage('Connection to server could not be established!');

end; .; branch code to handle RPC availability

XWB ARE RPCS AVAILABLE Example Checking RPC Availability on a Remote Server

Use this RPC to determine if a set of RPCs is available on a server. The RUN CONTEXT PARAMETER allows you to test availability on a local or remote server. The RPC INPUT PARAMETER passes the names and (optionally) minimum version number of the RPCs to be checked.

RETURN VALUE: A 0-based array. The index corresponds to the index of the RPC in the RPC Input Parameter. 1 = RPC Available 0 = RPC Not Available

RUN CONTEXT PARAMETER (Optional): Pass the run context (local or remote) of the RPC in Param[0].Value, and the type (literal) in Param[0].PType. Possible values are: · L = Check if available to be run locally (by a user logged into the server). · R = Check if available to be run remotely (by a user logged in a different server).

If this parameter is not sent, the RPC is checked for both local and remote, and both run contexts must be available for the return to be "1" (RPC Available). The check is done against the INACTIVE field in the REMOTE PROCEDURE file.

RPC INPUT PARAMETER: Pass a 0-based array of the names and (optionally) version numbers of RPCs to be tested in Param[1].Mult[], and the type (List) in Param[1].PType. The format is: RPCName^RPCVersionNumber

The RPCVersionNumber is used only if the Run Context parameter = “R”. If a numeric value is in the second ^-piece and Run Context = “R”, it will be checked against the value in the VERSION field of the REMOTE PROCEDURE file If the version number passed is less than or equal to the number in the VERSION field, the RPC will be marked available.

If the VERSION field is null, the check will fail for a numeric value in this parameter.

Also, the current context of your user must give them permission to execute the XWB ARE RPCS AVAILABLE (it must be included in the RPC multiple of the "B"-type option registered with the CreateContext function).

XWB ARE RPCS AVAILABLE Example brkrRPCBroker1.RemoteProcedure := 'XWB ARE RPCS AVAILABLE'; brkrRPCBroker1.Param[0].Ptype:= Literal; brkrRPCBroker1.Param[0].Value := 'L'; brkrRPCBroker1.Param[1].Ptype := List; brkrRPCBroker1.Param[1].Mult['0'] = 'MY FIRST RPC'; brkrRPCBroker1.Param[1].Mult['1'] = 'MY OTHER RPC^2'; try

   brkrRPCBroker1.Call;

except

 On EBrokerError do
   ShowMessage('Connection to server could not be established!');

end; .; branch code to handle availability of RPCs

Options For Running RPCs on a Remote Server The RPC Broker can be used to facilitate invocation of Remote Procedure Calls on a remote server. Applications can use either XWB DIRECT RPC or XWB REMOTE RPC to pass: · The desired remote server · The desired remote RPC · Any parameters for the remote RPC

The RPC Broker on the local server uses VISTA HL7 as a vehicle to pass the remote RPC name and parameters to the remote server. VISTA HL7 is used to send any results from the remote server back to the local server. The RPC Broker on the local server then passes the results back to the client application.

The local server is the server the user is logged into. The remote server is any server the user is not logged into.


USING XWB DIRECT RPC

XWB DIRECT RPC blocks all other Broker calls until the results of the remote RPC are returned. The data is passed and the user waits for the results to return from the remote system.


USING XWB REMOTE RPC

XWB REMOTE RPC is set up to allow other activity while the remote RPC is in process. In response to XWB REMOTE RPC the local server returns a HANDLE to the user application. At this point other Broker calls may commence while the server-to-server communication continues in the background.

XWB REMOTE STATUS CHECK allows the application to check the local server for the presence of results from the remote RPC. This RPC passes the HANDLE to the local server and receives back the status of the remote RPC.

XWB REMOTE GETDATA is the vehicle for retrieving the results from the remote RPC after the status check indicates that the data has returned to the local server. The RPC passes the HANDLE and receives back an array with whatever data has been sent back from the remote site.

XWB REMOTE CLEAR must be used to clear the data under the HANDLE in the ^XTMP Global.

Applications using XWB REMOTE XWB should use XWB DEFERRED CLEARALL on application close to clear all known data associated with the job on the server.

XWB DIRECT RPC and XWB REMOTE RPC are available only on a controlled subscription basis.

Checking RPC Availability on a Remote Server Applications can check the availability of RPCs on a remote server. Use: XWB DIRECT RPC or XWB REMOTE RPC

to pass: XWB IS RPC AVAILABLE or XWB ARE RPCS AVAILABLE

to the remote server.

The Run Context Parameter in XWB IS RPC AVAILABLE or XWB ARE RPCS AVAILABLE should be set to ‘R’ or null to check that the remote server will allow RPCs to be run by users not logged into that remote server.

XWB DIRECT RPC Example Use this RPC to request that an RPC be run on a remote system. This RPC blocks all other Broker calls until the results of the remote RPC are returned. Use XWB REMOTE RPC to allow other Broker activity while the remote RPC runs. See Options For Running RPCs on a Remote Server for a comparison of the two methods.

LOCATION PARAMETER: Pass the station number of the remote server in Param[0].Value, and the type (literal) in Param[0].PType.

RPC PARAMETER: Pass the name of the RPC to be run in Param[1].Value, and the type (literal) in Param[1].PType.

RPC VERSION PARAMETER (Optional): Pass minimum version of RPC to be run in Param[2].Value, and the type (literal) in Param[2].PType. It will be checked against the value in the VERSION field of the REMOTE PROCEDURE file on the remote server.

PARAMETERS TO THE REMOTE RPC: Pass up to seven parameters for the remote RPC in Param[3] through Param[9].

RETURN VALUE: An array with whatever data has been sent back from the remote site. In the case of an error condition the first node of the array is equal to a string with the syntax “-1^error text”.

XWB DIRECT RPC is available only on a controlled subscription basis.

XWB DIRECT RPC Example brkrRPCBroker1.RemoteProcedure := 'XWB DIRECT RPC'; brkrRPCBroker1.Param[0].Ptype:= Literal; brkrRPCBroker1.Param[0].Value := 'Station Number'; brkrRPCBroker1.Param[1].Ptype:= Literal; brkrRPCBroker1.Param[1].Value := 'XWB GET VARIABLE VALUE'; {no version numbers for remote RPC so null value in Param[2]} brkrRPCBroker1.Param[2].Ptype:= Literal; brkrRPCBroker1.Param[2].Value := ; brkrRPCBroker1.Param[3].Ptype:= Reference; brkrRPCBroker1.Param[3].Value := 'DUZ'; try

   brkrRPCBroker1.Call;

except

 On EBrokerError do
   ShowMessage('Connection to server could not be established!');

end; .; code to handle brkrRPCBroker1.Results[]

XWB REMOTE RPC Example Use this RPC to request that an RPC be run on a remote system. This RPC allows other Broker activity while the remote RPC runs. Use XWB DIRECT RPC to block all other Broker activity while the remote RPC runs. See Options For Running RPCs on a Remote Server for a comparison of the two methods.

XWB REMOTE RPC requests the remote RPC. The return value is a HANDLE that is used to check status and retrieve data. The following RPCs must be used to complete the transaction · XWB REMOTE STATUS CHECK · XWB REMOTE GETDATA · XWB REMOTE CLEAR


LOCATION PARAMETER: Pass the station number of the remote server in Param[0].Value, and the type (literal) in Param[0].PType.

RPC PARAMETER: Pass the name of the RPC to be run in Param[1].Value, and the type (literal) in Param[1].PType.

RPC VERSION PARAMETER (Optional): Pass minimum version of RPC to be run in Param[2].Value, and the type (literal) in Param[2].PType. It will be checked against the value in the VERSION field of the REMOTE PROCEDURE file on the remote server.

PARAMETERS TO THE REMOTE RPC: Pass up to seven parameters for the remote RPC in Param[3] through Param[9].

RETURN VALUE: An array. The first node is equal to a string that serves as a HANDLE. This HANDLE should be stored by the application and used to check the status and retrieve the data. In the case of an error condition the first node of the array is equal to a string with the syntax “-1^error text”.

XWB REMOTE RPC is available only on a controlled subscription basis.

XWB REMOTE RPC Example brkrRPCBroker1.RemoteProcedure := 'XWB REMOTE RPC'; brkrRPCBroker1.Param[0].Ptype:= Literal; brkrRPCBroker1.Param[0].Value := 'Station Number'; brkrRPCBroker1.Param[1].Ptype:= Literal; brkrRPCBroker1.Param[1].Value := 'MY RPC’; brkrRPCBroker1.Param[2].Ptype:= Literal; brkrRPCBroker1.Param[2].Value := '1'; brkrRPCBroker1.Param[3].Ptype:= Reference; brkrRPCBroker1.Param[3].Value := 'MY RPC PARAMETER'; try

   brkrRPCBroker1.Call;

except

 On EBrokerError do
   ShowMessage('Connection to server could not be established!');

end; .; code to store HANDLE returned in brkrRPCBroker1.Results[]

The application will need to use XWB REMOTE STATUS CHECK, XWB REMOTE GETDATA, and XWB REMOTE CLEAR to complete the transaction.

XWB REMOTE STATUS CHECK Example Use this RPC to check for results of XWB REMOTE RPC. Periodically call this RPC and pass the HANDLE returned by XWB REMOTE RPC.

RETURN VALUE: The return value is always an array. The first node of the array is equal to one of the following values: · “-1^Bad Handle -- An invalid handle has been passed. · “0^New” -- The request has been sent via VISTA HL7. · “0^Running” -- VISTA HL7 indicates that the message is being processed. · “1^Done” -- RPC has completed and the data has been returned to the local server. The data is not returned by this RPC. Use XWB REMOTE GETDATA to retrieve the data.


The second node of the array is the status from the HL7 package.

XWB REMOTE STATUS CHECK Example brkrRPCBroker1.RemoteProcedure := 'XWB REMOTE STATUS CHECK'; brkrRPCBroker1.Param[0].Value :='MYHANDLE'; brkrRPCBroker1.Param[0].PType := literal; try

   brkrRPCBroker1.Call;

except

 On EBrokerError do
   ShowMessage('Connection to server could not be established!');

end; .; code to handle results of check

XWB REMOTE GETDATA Example Use this RPC to retrieve the results of XWB REMOTE RPC. Before calling this RPC, use XWB REMOTE STATUS CHECK to ensure that the results have been returned to the local server. When the results have arrived, call this RPC and pass the HANDLE returned by XWB REMOTE RPC.

After the application is finished with the data on the server, it should use XWB REMOTE CLEAR to clear the ^XTMP global.

RETURN VALUE: An array containing the data. In the case of an error condition the first node of the array is equal to a string with the syntax “-1^error text”.

XWB REMOTE GETDATA Example brkrRPCBroker1.RemoteProcedure := 'XWB REMOTE GETDATA'; brkrRPCBroker1.Param[0].Value :='MYHANDLE'; brkrRPCBroker1.Param[0].PType := literal; try

   brkrRPCBroker1.Call;

except

 On EBrokerError do
   ShowMessage('Connection to server could not be established!');

end; .; code to handle data

XWB REMOTE CLEAR Example This RPC is used to clear the data created by a remote RPC under the HANDLE in the ^XTMP. Pass the HANDLE returned by XWB REMOTE RPC.

RETURN VALUE: An array. The first node in the array is equal to 1.

XWB REMOTE CLEAR Example brkrRPCBroker1.RemoteProcedure := 'XWB REMOTE CLEAR'; brkrRPCBroker1.Param[0].Value :='MYHANDLE'; brkrRPCBroker1.Param[0].PType := literal; try

   brkrRPCBroker1.Call;

except

 On EBrokerError do
   ShowMessage('Connection to server could not be established!');

end;

HANDLE

A HANDLE is a string returned by XWB REMOTE RPC or XWB DEFERRED RPC. The application should store the HANDLE and use it to check for the return of the data, retrieve the data, and clear the data from the server.

Overview of Deferred RPCs Remote Procedure Calls can now be run in the background with XWB DEFERRED RPC.


USING XWB DEFERRED RPC

XWB DEFERRED RPC is used to pass the name of the RPC to be run in deferred mode and any parameters associated with the deferred RPC. In response to this RPC the server returns a HANDLE to the user application. At this point other Broker calls may commence while the job runs in the background.

XWB DEFERRED STATUS allows the application to check the local server for the presence of results from the deferred RPC. This RPC passes the HANDLE to the local server and receives back the status of the remote RPC.

XWB DEFERRED GETDATA is the vehicle for retrieving the results from the remote RPC after the status check indicates that the data has returned to the local server. The RPC passes the HANDLE and receives back an array with whatever data has been returned by the deferred RPC.

XWB DEFERRED CLEAR must be used to clear the data under the HANDLE in the ^XTMP Global.

Applications using XWB DEFERRED RPC should use XWB DEFERRED CLEARALL on application close to clear all known data associated with the job on the server.

XWB DEFERRED RPC Example Use this RPC to request that an RPC be run in deferred mode. The return value is a HANDLE that is used to check status and retrieve data. The following RPCs must be used to complete the transaction: · XWB DEFERRED STATUS · XWB DEFERRED GETDATA · XWB DEFERRED CLEAR


RPC PARAMETER: Pass the name of the RPC to be run in Param[0].Value, and the type (literal) in Param[0].PType.

RPC VERSION PARAMETER (Optional): Pass minimum version of RPC to be run in Param[1].Value, and the type (literal) in Param[1].PType. It will be checked against the value in the VERSION field of the REMOTE PROCEDURE file on the remote server.

PARAMETERS TO THE REMOTE RPC: Pass up to eight parameters for the remote RPC in Param[2] through Param[9].

RETURN VALUE: An array. The first node is equal to a string that serves as a HANDLE. This HANDLE should be stored by the application and used to check the status and retrieve the data. In the case of an error condition the first node of the array is equal to a string with the syntax “-1^error text”.

XWB DEFERRED RPC Example brkrRPCBroker1.RemoteProcedure := 'XWB DEFERRED RPC'; brkrRPCBroker1.Param[0].Ptype:= Literal; brkrRPCBroker1.Param[0].Value := 'MY RPC’; brkrRPCBroker1.Param[1].Ptype:= Literal; brkrRPCBroker1.Param[1].Value := '1'; brkrRPCBroker1.Param[2].Ptype:= Reference; brkrRPCBroker1.Param[2].Value := 'MY RPC PARAMETER'; try

   brkrRPCBroker1.Call;

except

 On EBrokerError do
   ShowMessage('Connection to server could not be established!');

end; .; code to store HANDLE returned in brkrRPCBroker1.Results[0]


The application will need to use XWB DEFERRED STATUS, XWB DEFERRED GETDATA, AND XWB DEFERRED CLEAR to complete the transaction.

XWB DEFERRED STATUS Example Use this RPC to check for results of XWB DEFERRED RPC. Periodically, call this RPC and pass the HANDLE returned by XWB REMOTE RPC.

RETURN VALUE: The return value is always an array. The first node of the array is equal to one of the following values: · “-1^Bad Handle” – An invalid handle has been passed. · “0^New” -- The request has been sent via VISTA HL7. · “0^Running” -- VISTA HL7 indicates that the message is being processed. · “1^Done” -- RPC has completed and the data has been returned to the local server. The data s not returned by this RPC. Use XWB REMOTE GETDATA to retrieve the data.

XWB DEFERRED STATUS Example brkrRPCBroker1.RemoteProcedure := 'XWB DEFERRED STATUS'; brkrRPCBroker1.Param[0].Value :='MYHANDLE'; brkrRPCBroker1.Param[0].PType := literal; try

   brkrRPCBroker1.Call;

except

 On EBrokerError do
   ShowMessage('Connection to server could not be established!');

end; .; code to handle results of check

XWB DEFERRED GETDATA Example Use this RPC to retrieve the results of XWB DEFERRED RPC. Before calling this RPC, use XWB DEFERRED STATUS to ensure that the job has finished. When the results are available, call this RPC and pass the HANDLE returned by XWB DEFERRED RPC.

After the application is finished with the data on the server, it should use XWB DEFERRED CLEAR to clear the ^XTMP global.

RETURN VALUE: An array containing the data. In the case of an error condition the first node of the array is equal to a string with the syntax “-1^error text”.

XWB DEFERRED GETDATA Example brkrRPCBroker1.RemoteProcedure := 'XWB DEFERRED GETDATA'; brkrRPCBroker1.Param[0].Value :='MYHANDLE'; brkrRPCBroker1.Param[0].PType := literal; try

   brkrRPCBroker1.Call;

except

 On EBrokerError do
   ShowMessage('Connection to server could not be established!');

end; .; code to handle data

XWB DEFERRED CLEAR Example This RPC is used to clear the data created by a deferred RPC under the HANDLE in the ^XTMP global. Pass the HANDLE returned by XWB DEFERRED RPC.

RETURN VALUE: An array. The first node in the array is equal to 1.

XWB DEFERRED CLEAR Example brkrRPCBroker1.RemoteProcedure := 'XWB DEFERRED CLEAR'; brkrRPCBroker1.Param[0].Value :='MYHANDLE'; brkrRPCBroker1.Param[0].PType := literal; try

   brkrRPCBroker1.Call;

except

 On EBrokerError do
   ShowMessage('Connection to server could not be established!');

end;

XWB DEFERRED CLEARALL Example This RPC is used to CLEAR ALL the data known to a remote RPC or deferred RPC job in the ^XTMP global. It makes use of the list in ^TMP(“XWBHDL”,$J,handle). Applications using XWB REMOTE RPC or the XWB DEFERRED RPC should use this RPC on application close to clear all known data associated with the job on the server.

RETURN VALUE: An array. The first node in the array is equal to 1.

XWB DEFERRED CLEARALL Example brkrRPCBroker1.RemoteProcedure := 'XWB DEFERRED CLEAR'; try

   brkrRPCBroker1.Call;

except

 On EBrokerError do
   ShowMessage('Connection to server could not be established!');

end;

GetServerIP Function Example The GetServerIP function provides a means for determining the Internet Protocol (IP) address for a specified server address. The value returned is a string containing the IP address, or if it could not be resolved, the string "Unknown!"

function GetServerIP(ServerName: string): string;

GetServerIP Example

 //  include the unit RpcConf1 in the Uses clause
 //  An edit box on the form is assumed to be named edtIPAddress
 //  Another edit box (edtInput) is used to input a desired server name

uses RpcConf1;

procedure Tform1.Button1Click(Sender: TObject); var

 ServerName: string;

begin

 ServerName := 'forum.med.va.gov';
 edtIPAddress.Text := GetServerIP(edtInput.Text);
   // For Forum.va.gov returns '152.128.1.25'
   // For garbage returns 'Unknown!'

end;

ChangeVerify Function The ChangeVerify function can be used to provide the user with the ability to change his/her Verify code.

function ChangeVerify(RPCBroker: TRPCBroker): Boolean;

Argument: RPCBroker -- The Broker instance for the account on which the Verify code is to be changed.

Result: The return value indicates whether the user changed their Verify code (True) or not (False).

SilentChangeVerify Function The SilentChangeVerify function can be used to change the Verify code for a user without any windows being displayed.

function SilentChangeVerify(RPCBroker: TRPCBroker; OldVerify, NewVerify1, NewVerify2: String; var Reason: String): Boolean;

Arguments: RPCBroker -- The current instance of the Broker for the account for which the Verify code is to be changed. OldVerify -- The string representing the current Verify code for the user. NewVerify1 -- A string representing the new Verify code for the user. NewVerify2 -- A second independent entry for the string representing the new Verify code for the user. Reason -- A string that on return will contain the reason why the Verify code was not changed (if the result value is False).

Result: The return value indicates whether the Verify code was successfully changed (True) or not (False). If the result is False, the reason for the failure will be in the Reason argument.

CheckCmdLine Function With Patch XWB*1.1*13, the CheckCmdLine method was changed from a procedure to a function with a Boolean return value.

function CheckCmdLine(SLBroker: TRPCBroker): Boolean;

Argument: SLBroker -- The instance of the Broker with which information on the command line should be used, and to be used for the connection, if a Silent Login is possible.

Result: The return value indicates whether the information on the command line was sufficient to connect the RPCBroker instance to the specified Server/ListenerPort. If the value is True the connection has already been made. Otherwise, the Broker is not connected to the server.

StartProgSLogin Method The StartProgSLogin method can be used to initiate another program with information sufficient for a Silent Login, or it can be used to launch a standalone program that does not use a TRPCBroker connection. If the program is being used to launch another executable with information for a Silent Login, it is recommended that the CheckCmdLine function be used in the program being launched (since this function does use the command line information to make a Silent Login if possible).

procedure StartProgSLogin(const ProgLine: String; ConnectedBroker: TRPCBroker);

Argument: ProgLine -- This is the command line that should be used as the basis for launching the executable. It would contain the executable (and path, if not in the working directory or in the system path) and any command line arguments desired. If the ConnectedBroker argument is not nil, then the server address, the ListenerPort, Division, and ApplicationToken will be added to the command line and the application launched. ConnectedBroker -- This is the instance of the TRPCBroker that should be used to obtain an ApplicationToken for a Silent Login. The server address and ListenerPort for this instance will be used as command line arguments for launching the application, so that it will make a connection to the same Server/Port combination. If the application to be launched is not related to the TRPCBroker, then this argument should be set to nil.


Example1:

To launch a program, Sample1, with command line arguments xval=’MyData’ and yval=’YourData’, and connect with a Silent Login (which would be handled in Sample1.exe via the CheckCmdLine method): MyCommand := ‘C:\Program Files\VISTA\Test1\Sample1.exe xval=MyData yval=YourData’; StartProgSLogin(MyCommand, RPCBroker1);

This would result in the following command line being used to launch the application:

C:\Program Files\VISTA\Test1\Sample1.exe xval=MyData yval=YourData s=ServerName p=9200 d=Division h=AppHandleValue


Example2:

To launch a program unrelated to TRPCBroker and server connections (e.g., Microsoft Notepad), the command line as desired is used as the first argument, and the value nil is used as the second argument:

MyCommand := ‘Notepad logtable.txt’; StartProgSLogin(MyCommand, nil);

RPC Broker 32-bit DLL Interface Introduction The functionality of the TRPCBroker component for Delphi is provided in a 32-bit Dynamic Link Library (DLL) interface, in BAPI32.DLL. This enables the use of any development product that can access Windows 32-bit DLLs to create applications that communicate with M servers through the RPC Broker.

In Delphi, you have direct access to the TRPCBroker component itself, and its properties and methods. In other development environments, you can only access the properties and methods of the TRPCBroker component through DLL functions. So to understand the DLL interface, you should understand how the TRPCBroker component is used in its native environment (Delphi). DLL Exported Functions


The following special issues should be considered when accessing RPC Broker functionality through its DLL: RPC Results from DLL Calls GetServerInfo Function and the DLL


Header Files

Header files for using the DLL are provided for C (BAPI32.H), C++ (BAPI32.HPP), and Visual Basic (BAPI32.BAS). Guidelines for Calling DLL from C++ Guidelines for Calling DLL from C Guidelines for Calling DLL from Visual Basic


Sample DLL Application

The VB5EGCHO sample application, distributed with the Broker Development Kit (BDK), demonstrates use of the RPC Broker 32-bit DLL from Microsoft Visual Basic. The source code is located in the ..\BDK32\Samples\Vb5Egcho directory.

RPC Results from DLL Calls When executing an RPC on an M server, results from the RPC are returned as a text stream. This text stream may or may not have embedded <CR><LF> character combinations.

In Delphi, when you call an RPC using the TRPCBroker component directly, the text stream returned from an RPC is automatically parsed and returned in the TRPCBroker component's Results property, either in Results[0] or in multiple Results nodes. If there are no embedded <CR><LF> character combinations in the text stream, only Results[0] is used. If there are embedded <CR><LF> character combinations, results are placed into separate Results nodes based on the <CR><LF> delimiters.

When using the DLL interface, the return value is a text stream, but no processing of the text stream is performed for you. It is up to you to parse out what would have been individual Results nodes in Delphi, based on the presence of any <CR><LF> character combinations in the text stream.

You must create a character buffer large enough to receive the entire return value of an RPC.

GetServerInfo Function and the DLL When you use the TRPCBroker component for Delphi, you are able to call the GetServerInfo function to retrieve the end-user workstation's server and port settings.

The functionality provided by GetServerInfo is not currently available through the RPC Broker 32-bit DLL interface. A future version of the RPC Broker will provide access to the GetServerInfo functionality for DLL users.

To work around this for now, when using the RPC Broker 32-bit DLL, you should ~|Prompt]]prompt the user directly for the server and port to connect to.

DLL Exported Functions The following functions for TRPCBroker components are exported in BAPI32.DLL: RPCBCall Execute an RPC. RPCBCreate Create a TRPCBroker component. RPCBCreateContext Create context. RPCBFree Destroy a TRPCBroker component. RPCBMultItemGet Get value of a Mult item in a Param. RPCBMultPropGet Get value of a Mult property in a Param. RPCBMultSet Set a Mult item in a Param to a value. RPCBMultSortedSet Sorts a Mult Param property. RPCBParamGet Get the value of a Param. RPCBParamSet Set the value of a Param. RPCBPropGet Get the value of a TRPCBroker component property. RPCBPropSet Set the value of a TRPCBroker component property.

RPCBCall Function Examples Executes a remote procedure call, and fills the passed buffer with the data resulting from the call. This is equivalent to the TRPCBroker component's Call method.


Declarations Delphi procedure RPCBCall(const RPCBroker: TRPCBroker; CallResult: PChar); C char *(__stdcall *RPCBCall) (void *, char *); C++ char * RPCBCall( char * s); VB Sub RPCBCall (ByVal intRPCBHandle As Long, ByVal strCallResult As String)


Parameter Description RPCBroker Handle of the Broker component that contains the name of the remote procedure and all of the required parameters. CallResult An empty character buffer that the calling application must create (allocate memory for) before making this call. This buffer is filled with the result of the call.

See RPC Limits for information about the size of parameters and results that can be passed to and returned from the TRPCBroker component.

RPCBCall Examples C

RPCBCall(RPCBroker, Value);


C++

// MyInstance is defined as an instance of the TRPCBroker. MyInstance.RPCBCall( strbuffer);


Visual Basic

Call RPCBCall(intRPCBHandle, strBuffer)

RPCBCreate Function Examples Creates a new Broker component for the application, which can then be used to connect to the server and call remote procedures.


Declarations Delphi function RPCBCreate: TRPCBroker; C void * (__stdcall *RPCBCreate)(void); C++ N/A (encapsulated in TRPCBroker class definition) VB Function RPCBCreate () As Long


Return Value A handle for the TRPCBroker component created.

RPCBCreate Examples C

// Create the TRPCBroker component instance. RPCBroker = RPCBCreate();


Visual Basic

intRPCBHandle = RPCBCreate()

RPCBCreateContext Function Examples This procedure calls the TRPCBroker component's CreateContext method to set up the environment on the server for subsequent RPCs.


Declarations Delphi function RPCBCreateContext(const RPCBroker: TRPCBroker; const Context: PChar): boolean; C bool (__stdcall *RPCBCreateContext) (void *, char *); C++ bool RPCBCreateContext ( char * s); VB Function RPCBCreateContext (ByVal intRPCBHandle As Long, ByVal strContext As String) As Integer


Return Value True/1 if context could be created; false/0 if context could not be created.


Parameter Description RPCBroker Handle of the TRPCBroker component. Context Null-terminated string identifying the option on the server for which subsequent RPCs are registered.

RPCBCreateContext Examples C

// XWB EGCHO is a "B" (Broker) type option in the OPTION file. result = RPCBCreateContext(RPCBroker, "XWB EGCHO");


C++

// XWB EGCHO is a "B" (Broker) type option in the OPTION file. MyInstance.RPCBCreateContext("XWB EGCHO");


Visual Basic

intResult = RPCBCreateContext(intRPCBHandle, "MY APPLICATION") 'where MY APPLICATION is a "B" (Broker) type option in the Option file.

RPCBFree Function Examples Destroys the Broker component and releases associated memory.

Declarations Delphi procedure RPCBFree(RPCBroker: TRPCBroker); C void (__stdcall *RPCBFree)(void *); C++ N/A (encapsulated in TRPCBroker class definition) VB Sub RPCBFree (ByVal intRPCBHandle As Long)


Parameter Description RPCBroker Handle of the TRPCBroker component to destroy.

RPCBFree Examples C

// Destroy the TRPCBroker component instance. RPCBFree(RPCBroker);


Visual Basic

RPCBFree (intRPCBHandle)

RPCBMultItemGet Function Examples Returns a requested item in a TRPCBroker Param property's Mult property.


Declarations Delphi procedure RPCBMultItemGet (const RPCBroker: TRPCBroker; ParamIndex: integer; Subscript, Value: PChar); C void (__stdcall *RPCBMultItemGet) (void *, int, char *, char *); C++ void RPCBMultItemGet ( int i, char * s, char * t); VB Sub RPCBMultItemGet (ByVal intRPCBHandle As Long, ByVal intParIdx As Integer, ByVal strSubscript As String, ByVal strValue As String)


Parameter Description RPCBroker Handle of the TRPCBroker component. ParamIndex Integer index of the parameter that contains the Mult property. Subscript Null-terminated string identifying the Mult element to get. Value An empty buffer that the calling application must create (allocate memory for) before making this call. This buffer will be filled with value of the Mult property item.

See RPC Limits for information about the size of parameters and results that can be passed to and returned from the TRPCBroker component.

RPCBMultItemGet Examples C

// The following corresponds to getting the value of PARAM[0].Mult["0"] RPCBMultItemGet(RPCBroker, 0 , "0", Value);


C++

MyInstance.RPCBMultItemGet(0 , "0", Value);


Visual Basic

Call RPCBMultItemGet(intRPCBHandle, 0, "0", strResult)

RPCBMultPropGet Function Examples Returns a selected property value of a TRPCBroker Param property's Mult property.


Declarations Delphi procedure RPCBMultPropGet(const RPCBroker: TRPCBroker; ParamIndex: integer; Prop,Value: PChar); C void (__stdcall *RPCBMultPropGet) (void *, int, char *, char *); C++ void RPCBMultPropGet (int i , char * s, char * t); VB Sub RPCBMultPropGet (ByVal intRPCBHandle As Long, ByVal intParIdx As Integer, ByVal strProp As String, ByRef strValue As String)


Parameter Description RPCBroker Handle of the TRPCBroker component. ParamIndex Integer index of the parameter that contains the Mult property. Prop Null-terminated string identifying the name of the TMult property to get. Value An empty buffer that the calling application must create (allocate memory for) before making this call. This buffer will be filled with value of the Mult property that is in the Prop.

See RPC Limits for information about the size of parameters and results that can be passed to and returned from the TRPCBroker component.

RPCBMultPropGet Examples C

RPCBMultPropGet(RPCBroker, 0, "Count", Value);


C++

MyInstance.RPCBMultPropGet(0, "Count", Value);


Visual Basic

Call RPCBMultPropGet(intRPCBHandle, 0, "Count", strResult)

RPCBMultSet Function Examples Sets an item in a TRPCBroker Param property's Mult property to a value.


Declarations Delphi procedure RPCBMultSet(const RPCBroker: TRPCBroker; ParamIndex: integer; Subscript, Value: PChar); C void (__stdcall *RPCBMultSet) (void *, int, char *, char *); C++ void RPCBMultSet ( int i, char * s, char * t); VB Sub RPCBMultSet (ByVal intRPCBHandle As Long, ByVal intParIdx As Integer, ByVal strSubscript As String, ByVal strValue As String)


Parameter Description RPCBroker Handle of the TRPCBroker component. ParamIndex Integer index of the parameter that contains the Mult property. Subscript Null-terminated string of the Mult item to set. Value Null-terminated string containing the value that the Mult item should be set to.

See RPC Limits for information about the size of parameters and results that can be passed to and returned from the TRPCBroker component.

RPCBMultSet Examples C

RPCBMultSet(RPCBroker, 0, "1", "12/19/97");


C++

MyInstance.RPCBMultSet(0, "1", "12/19/97");


Visual Basic

Call RPCBMultSet(intRPCBHandle, 0, "1", "12/19/97")

RPCBMultSortedSet Function Examples Sets the Sorted property of a Mult property. In essence, sorts and keeps the Mult property sorted or just leaves it in the order it is populated.


Declarations Delphi procedure RPCBMultSortedSet(const RPCBroker: TRPCBroker; ParamIndex: integer; Value: boolean); C void (__stdcall *RPCBMultSortedSet) (void *, int, bool); C++ void RPCBMultSortedSet (int i, bool v); VB Sub RPCBMultSortedSet (ByVal intRPCBHandle As Long, ByVal intParIdx As Integer, ByVal intValue As Integer)


Parameter Description RPCBroker Handle of the TRPCBroker component. ParamIndex Integer index of the parameter that contains the Mult property. Value Can be either a Boolean or, if the calling application language does not support Boolean type, can be an integer. True or 1 will sort the Mult and keep it sorted thereafter when other elements are added. False or 0 will not sort the Mult and the elements will be stored in the order they are added.

RPCBMultSortedSet C

RPCBMultSortedSet(RPCBroker, 0, 1);


C++

MyInstance.RPCBMultSortedSet(0, 1);


Visual Basic

Call RPCBMultPropGet(intRPCBHandle, 0, 1)

RPCBParamGet Function Examples Returns two values in two parameters: the value and the parameter type of a Param item.

You can compare the returned parameter type to the following enumerated values: literal, reference and list.


Declarations Delphi procedure RPCBParamGet(const RPCBroker: TRPCBroker; ParamIndex: integer; var ParamType: TParamType; var ParamValue: PChar); C void (__stdcall *RPCBParamGet) (void *, int, int, char *); C++ void RPCBParamGet ( int i, int j, char * s); VB Sub RPCBParamGet (ByVal intRPCBHandle As Long, ByVal intParIdx As Integer, ByVal intParTyp As Integer, ByVal intParVal As String)


Parameter Description RPCBroker Handle of the TRPCBroker component. ParamIndex Integer index of the parameter to get value of. ParamType This variable, after making the RPCBParamGet call, is filled with PType property of a Param[ParamIndex]. ParamValue An empty buffer that you must create (allocate memory for) before making this call. This buffer, after making the RPCBParamGet call, is filled with Value of a Param[ParamIndex].

See RPC Limits for information about the size of parameters and results that can be passed to and returned from the TRPCBroker component.

RPCBParamGet Examples C

// PType and Value are variables to retrieve values into. RPCBParamGet(RPCBroker, 0, PType, Value);


C++

// PType and Value are variables to retrieve values into. MyInstance.RPCBParamGet(0, PType, Value);


Visual Basic

Call RPCBParamGet(intRPCBHandle, 0, PType, strResult) ' where PType and strResult are variables to retrieve values into

RPCBParamSet Function Examples Sets one Param item's Value and PType properties, in a single call.


Declarations Delphi procedure RPCBParamSet(const RPCBroker: TRPCBroker; const ParamIndex: integer; const ParamType: TParamType; const ParamValue: PChar); C void (__stdcall *RPCBParamSet) (void *, int, int, char *); C++ void RPCBParamSet ( int i, int j, char * s); VB Sub RPCBParamSet (ByVal intRPCBHandle As Long, ByVal intParIdx As Integer, ByVal intParTyp As Integer, ByVal intParVal As String)


Parameter Description RPCBroker Handle of the TRPCBroker component. ParamIndex Integer index of the parameter . ParamType Set to the parameter type for the parameter you are setting. The value should be one of the integer values that are valid as a PType: 0 (literal), 1 (reference) and 2 (list). You can use the enumerated values literal, reference and list, as declared in the C, C++ , or Visual Basic header file. ParamValue Null-terminated string containing the Value to set.

See RPC Limits for information about the size of parameters and results that can be passed to and returned from the TRPCBroker component.

RPCBParamSet Examples C

RPCBParamSet(RPCBroker, 0, reference, "DUZ");


C++

MyInstance.RPCBParamSet(0, reference, "DUZ");


Visual Basic

Call RPCBParamSet(intRPCBHandle, 0, literal, Text3.Text)

RPCBPropGet Function Examples Returns a requested property of a TRPCBroker component.


Declarations Delphi procedure RPCBPropGet(const RPCBroker: TRPCBroker; const Prop: PChar; {var} Value: PChar); C void (__stdcall *RPCBPropGet) (void *, char *, char *); C++ void RPCBPropGet ( char * s, char * t); VB Sub RPCBPropGet (ByVal intRPCBHandle As Long, ByVal strProp As String, ByVal strValue As String)


Parameter Description RPCBroker Handle of the TRPCBroker component. Prop Null-terminated string of the property to get. Not case-sensitive. Valid properties to get are: ClearParameters, ClearResults, Connected, DebugMode, ListenerPort, RemoteProcedure, RPCTimeLimit, RPCVersion, and Server. Value An empty buffer that you must create (allocate memory for) before making this call. After this call, the buffer is filled with value of the property that is in the Prop. This procedure takes care of all the necessary type conversions. Boolean property values are returned as 1 (True) or 0 (False).

RPCBPropGet Examples C

RPCBPropGet(RPCBroker, "Connected", Value);


C++

MyInstance.RPCBPropGet("Connected", Value);


Visual Basic

Call RPCBPropGet(intRPCBHandle, "Server", strResult)

RPCBPropSet Function Examples Sets a TRPCBroker property to some value.


Declarations Delphi procedure RPCBPropSet(const RPCBroker: TRPCBroker; Prop,Value: PChar); C void (__stdcall *RPCBPropSet) (void *, char *, char *); C++ void RPCBPropSet ( char * s, char * t); VB Sub RPCBPropSet (ByVal intRPCBHandle As Long, ByVal strProp As String, ByVal strValue As String)


Parameter Description RPCBroker Handle of the TRPCBroker component. Prop Null-terminated string of the property to set. Not case-sensitive. Valid properties to set are: ClearParameters, ClearResults, Connected, DebugMode, ListenerPort, RemoteProcedure, RPCTimeLimit, RPCVersion, and Server. Value Null-terminated string of the value to which the Prop property should be set. This procedure takes care of converting the passed in value to whatever type the property expects. For Boolean properties, pass in 1 (True) or 0 (False).

RPCBPropSet Examples C

RPCBPropSet(RPCBroker, "ListenerPort", "9200");


C++

MyInstance.RPCBPropSet("ListenerPort", "9200");


Visual Basic

Call RPCBPropSet(intRPCBHandle, "Server", cboServer.Text)

Guidelines for C++ Overview The BAPI32.HPP header file defines a class "wrapper" around the RPC Broker 32-bit DLL, defining a TRPCBroker C++ class. Objects of this class include all functions exported in the DLL, as methods of the TRPCBroker C++ class.

TRPCBroker C++ class methods.

One feature of wrapping a class around the RPC Broker 32-bit DLL is that all the ordinary details of working with a DLL (loading the DLL, getting the addresses of the functions in the DLL, and freeing the DLL) are done within the class definition. When you initialize the class, all of the details of loading and unloading the detail (LoadLibrary, GetProcAddress, and FreeLibrary) are done for you.

To use objects of the class, simply initialize the class, and then create and destroy objects of the class.

To use the TRPCBroker C++ class that encapsulates BAPI32.DLL: 1. Initialize the Class 2. Create Broker Instances 3. Connect to the Server 4. Execute RPCs 5. Destroy Broker Instances

C++: TRPCBroker C++ Class Methods The functions in the RPC Broker 32-bit DLL are encapsulated in the following TRPCBroker C++ class methods:

DLL Function TRPCBroker C++ class method RPCBCall char * RPCBCall( char * s); RPCBCreateContext bool RPCBCreateContext ( char * s); RPCBMultItemGet void RPCBMultItemGet ( int i, char * s, char * t); RPCBMultPropGet void RPCBMultPropGet (void * ptr, int i , char * s, char * t); RPCBMultSet void RPCBMultSet ( int i, char * s, char * t); RPCBMultSortedSet void RPCBMultSortedSet (void * ptr, int i, bool v); RPCBParamGet void RPCBParamGet ( int i, int j, char * s); RPCBParamSet void RPCBParamSet ( int i, int j, char * s); RPCBPropGet void RPCBPropGet ( char * s, char * t); RPCBPropSet void RPCBPropSet ( char * s, char * t);

C++: Initialize the Class The first step to using the RPC Broker 32-bit DLL in a C++ program is to load the DLL and get the process addresses for the exported functions.

To initialize access to the Broker DLL functions:

1. Include bapi32.hpp in your program.

  1. include bapi32.hpp

This includes the TRPCBroker C++ class definition in your program. When you (later) create a TRPCBroker C++ class object in your program, the class definition takes care of loading the DLL if not already loaded, mapping the DLL functions if not already mapped, and creating the instance of the TRPCBroker component.

C++: Create Broker Instances To create instances of TRPCBroker C++ class objects in your C++ program:

1. Create a variable of type TRPCBroker. This initializes the TRPCBroker class, creates a TRPCBroker C++ class object instance, and creates a TRPCBroker component.

// Initialize the TRPCBroker class. TRPCBroker RPCInst;

The properties and methods of the created TRPCBroker component can be accessed through the TRPCBroker C++ class object.

C++: Connect to the Server To connect to the server from your C++ program:

1. Set the server and port to connect to.

// Set the Server and Port properties to determine where to connect. RPCInst.RPCBPropSet("Server", server); RPCInst.RPCBPropSet("ListenerPort", "9200");

2. Set the Connected property to true; this attempts a connection to the server.

// Set the Connected property to True, to connect. RPCInst.RPCBPropSet("Connected", "1");

3. Check if you are still connected. If so, you can continue (your connection was made). If not, you should quit or branch accordingly.

// If still connected, can continue. RPCInst.RPCBPropGet("Connected", Value); if (atoi(Value) != 1) return false;

4. Attempt to create context for your application's "B"-type option. If you can't create context, you should quit or branch accordingly. If RPCBCreateContext returns True, then you are ready to call all RPCs registered to your application's "B"-type option.

// Create Context for your application's option (in this case, XWB EGCHO). result = RPCInst.RPCBCreateContext("XWB EGCHO"); return result;

C++: Execute RPCs If you can make a successful connection to the RPC Broker server, and create an application context, you can execute any RPCs registered to your context.

To execute RPCs from your C++ program:

1. Create a character buffer large enough to hold your RPC's return value:

char Value [1024];

2. Set the RemoteProcedure property of the TRPCBroker component to the RPC to execute.

RPCInst.RPCBPropSet("RemoteProcedure","XWB GET VARIABLE VALUE");

3. Set the Param values for any parameters needed by the RPC. In the following example, one TRPCBroker Param node is set (the equivalent of Param[0]): a. A value of 0 for parameter 1 denotes the integer index of the Param node being set (Param[0]). b. A value of reference for parameter 2 denotes the setting for the equivalent of Param[0].PType. This uses the enumerated values for PType declared in the header file. c. A value of "DUZ" for parameter 3 denotes that the equivalent of Param[0].Value is "DUZ".

RPCInst.RPCBParamSet(0, reference, "DUZ");

4. Use the RPCBCall method to execute the RPC.

RPCInst.RPCBCall(Value);

The return value from the RPC is returned in the first parameter (in this case, the Value character buffer).

C++: Destroy Broker Instances You do not need to do anything special to free up memory used by the TRPCBroker component instances and their companion TRPCBroker C++ class objects. They are automatically destroyed when your program terminates, just as normal variables are automatically destroyed.

Also, when your program terminates, the FreeLibrary Windows API call is automatically executed to unload the RPC Broker 32-bit DLL, so there is no need to do this manually.

Guidelines for C Overview The BAPI32.H header file defines the function prototypes for all functions exported in the RPC Broker 32-bit DLL. DLL Exported Functions


To use the DLL Broker functions, using C, exported in BAPI32.DLL: 1. Initialize -- LoadLibrary and GetProcAddress 2. Create Broker Components 3. Connect to the Server 4. Execute RPCs 5. Destroy Broker Components

C: Initialize -- LoadLibrary and GetProcAddress The first step to using the RPC Broker 32-bit DLL in a C program is to load the DLL and get the process addresses for the exported functions.

To initialize access to the Broker DLL functions:

1. Use the Windows API LoadLibrary function to load the DLL.

HINSTANCE hLib = LoadLibrary("bapi32.dll"); if((unsigned)hLib<=HINSTANCE_ERROR) {

  /* Add your error handler for case where library fails to load. */
  return 1;

}

2. If you successfully load the DLL, map function pointers to the addresses of the functions in the DLL that you need for your application.

RPCBCreate = (void *(__stdcall*)()) GetProcAddress(hLib, "RPCBCreate"); RPCBFree = (void (__stdcall*)(void *)) GetProcAddress(hLib, "RPCBFree"); RPCBCall = (char *(__stdcall*)(void *, char *)) GetProcAddress(hLib, "RPCBCall"); RPCBCreateContext = (bool (__stdcall*)(void *, char *)) GetProcAddress(hLib, "RPCBCreateContext"); RPCBMultSet = (void (__stdcall*)(void *, int, char *, char *)) GetProcAddress(hLib, "RPCBMultSet"); RPCBParamGet = (void (__stdcall*)(void *, int, int, char *)) GetProcAddress(hLib, "RPCBParamGet"); RPCBParamSet = (void (__stdcall*)(void *, int, int, char *)) GetProcAddress(hLib, "RPCBParamSet"); RPCBPropGet = (void (__stdcall*)(void *, char *, char *)) GetProcAddress(hLib, "RPCBPropGet"); RPCBPropSet =(void (__stdcall*)(void *, char *, char *)) GetProcAddress(hLib, "RPCBPropSet"); // // GetProcAddress, returns null on failure. // if( RPCBCreate == NULL || RPCBFree == NULL || RPCBCall == NULL || RPCBCreateContext == NULL

  || RPCBMultSet == NULL || RPCBParamGet == NULL || RPCBParamSet == NULL || RPCBPropGet == NULL
  || RPCBPropSet == NULL)

{ /* Add your error handler for cases where functions are not found. */

  return 1;

}

Now you can use functions exported in the DLL.

C: Create Broker Components To create TRPCBroker components in your C program:

1. Create a pointer for the TRPCBroker component.

// Generic pointer for the TRPCBroker component instance. void * RPCBroker;

2. Call the RPCBCreate method to create a TRPCBroker component and return its address into the pointer you created:

// Create the TRPCBroker component instance. RPCBroker = RPCBCreate();

Now you can use the pointer to the created Broker component to call its methods.

C: Connect to the Server To connect to the server from your C program:

1. Set the server and port to connect to.

// Set the Server and Port properties to determine where to connect. RPCBPropSet(RPCBroker,"Server", "BROKERSERVER"); RPCBPropSet(RPCBroker, "ListenerPort", "9200");

2. Set the Connected property to true; this attempts a connection to the server.

// Set the Connected property to True, to connect. RPCBPropSet(RPCBroker, "Connected", "1");

3. Check if you are still connected. If so, you can continue (your connection was made). If not, you should quit or branch accordingly.

// If still connected, can continue. RPCBPropGet(RPCBroker, "Connected", Value); if (atoi(Value) != 1) return false;

4. Attempt to create context for your application's "B"-type option. If you can't create context, you should quit or branch accordingly. If RPCBCreateContext returns True, then you are ready to call all RPCs registered to your application's "B"-type option.

// Create Context for your application's option (in this case, XWB EGCHO). result = RPCBCreateContext(RPCBroker, "XWB EGCHO"); return result;

C: Execute RPCs If you can make a successful connection to the RPC Broker server, and create an application context, you can execute any RPCs registered to your context.

To execute RPCs from your C program:

1. Create a character buffer large enough to hold your RPC's return value:

static char Value [1024];

2. Set the RemoteProcedure property of the TRPCBroker component to the RPC to execute.

RPCBPropSet(RPCBroker, "RemoteProcedure","XWB GET VARIABLE VALUE");

3. Set the Param values for any parameters needed by the RPC. In the following example, one TRPCBroker Param node is set (the equivalent of Param[0]): a. A value of 0 for parameter 2 denotes the integer index of the Param node being set (Param[0]). b. A value of reference for parameter 3 denotes the setting for the equivalent of Param[0].PType. This uses the enumerated values for PType declared in the header file. c. A value of "DUZ" for parameter 4 denotes that the equivalent of Param[0].Value is "DUZ".

RPCBParamSet(RPCBroker, 0, reference, "DUZ");

4. Use the RPCBCall method to execute the RPC.

RPCBCall(RPCBroker, Value);

The return value from the RPC is returned in the second parameter (in this case, the Value character buffer).

C: Destroy Broker Components When you are done using any TRPCBroker component, you should call its destroy method to free it from memory.

To destroy TRPCBroker components from your C program:

1. Make sure the TRPCBroker component is not connected.

RPCBPropSet(RPCBroker, "Connected", "0");

2. Call the RPCBFree method to destroy the object.

// Destroy the RPCBroker component instance. RPCBFree(RPCBroker);

3. When you have destroyed all TRPCBroker components, but before your application terminates, you should call the Windows API FreeLibrary function to unload the DLL.

FreeLibrary(hLib);

Guidelines for Visual Basic Overview The BAPI32.BAS header file defines the function prototypes for all functions exported in the RPC Broker 32-bit DLL.

DLL Exported Functions


To use the DLL Broker functions, using Visual Basic, exported in BAPI32.DLL: 1. Initialize 2. Create Broker Components 3. Connect to the Server 4. Execute RPCs 5. Destroy Broker Components


Sample DLL Application

The VB5EGCHO sample application, distributed with the Broker Development Kit, demonstrates use of the RPC Broker 32-bit DLL from Microsoft Visual Basic. The source code is located in the ..\BDK32\Samples\Vb5Egcho directory.

Visual Basic: Initialize The first step to using the RPC Broker 32-bit DLL in a Visual Basic program is to load the DLL and get the process addresses for the exported functions.

To initialize access to the Broker DLL functions:

1. Include BAPI32.BAS as a module in your Visual Basic program.

Visual Basic takes care of loading the DLL and mapping its functions.

Visual Basic: Create Broker Components To create TRPCBroker components in your Visual Basic program:

1. Create a variable to be a handle for the TRPCBroker component.

Public intRPCBHandle As Long

2. Call the RPCBCreate method to create a TRPCBroker component and return its address into the variable you created:

intRPCBHandle = RPCBCreate()

Now you can use the handle to the created Broker component to call its methods.

Visual Basic: Connect to the Server To connect to the server from your Visual Basic program:

1. Set the server and port to connect to.

Call RPCBPropSet(intRPCBHandle, "Server", "BROKERSERVER") Call RPCBPropSet(intRPCBHandle, "ListenerPort", "9200")

2. Set the Connected property to true; this attempts a connection to the server.

Call RPCBPropSet(intRPCBHandle, "Connected", "1")

3. Check if you are still connected. If so, you can continue (your connection was made). If not, you should quit or branch accordingly.

RPCBPropGet(intRPCBHandle, "Connected", strResult)

4. Attempt to create context for your application's "B"-type option. If you can't create context, you should quit or branch accordingly. If RPCBCreateContext returns True, then you are ready to call all RPCs registered to your application's "B"-type option.

intResult = RPCBCreateContext(intRPCBHandle, "MY APPLICATION")

Visual Basic: Execute RPCs If you can make a successful connection to the RPC Broker server, and create an application context, you can execute any RPCs registered to your context.

To execute RPCs from your Visual Basic program:

1. Create a character buffer large enough to hold your RPC's return value:

Public strBuffer As String * 40000

2. Set the RemoteProcedure property of the TRPCBroker component to the RPC to execute.

Call RPCBPropSet(intRPCBHandle, "RemoteProcedure", "XWB GET VARIABLE VALUE")

3. Set the Param values for any parameters needed by the RPC. In the following example, one TRPCBroker Param node is set (the equivalent of Param[0]): a. A value of 0 for parameter 2 denotes the integer index of the Param node being set (Param[0]). b. A value of reference for parameter 3 denotes the setting for the equivalent of Param[0].PType. This uses the enumerated values for PType declared in the header file. c. A value of "DUZ" for parameter 4 denotes that the equivalent of Param[0].Value is "DUZ".

Call RPCBParamSet(intRPCBHandle, 0, reference, "DUZ");

4. Use the RPCBCall method to execute the RPC.

Call RPCBCall(intRPCBHandle, strBuffer)

The return value from the RPC is returned in the second parameter (in this case, the Value character buffer).

Visual Basic: Destroy Broker Components When you are done using any TRPCBroker component, you should call its destroy method to free it from memory.

To destroy TRPCBroker components from your Visual Basic program:

1. Make sure the TRPCBroker component is not connected.

Call RPCBPropSet(intRPCBHandle, "Connected", "0")

2. Call the RPCBFree method to destroy the object.

RPCBFree(intRPCBHandle)

Visual Basic takes care of the details of unloading the DLL.

Debugging and Troubleshooting Overview The Broker Development Kit provides facilities for debugging and troubleshooting your applications. How to Debug Your Application Identifying the Listener Process Identifying the Handler Process RPC Error Trapping Testing Your RPCBroker Connection Memory Leaks Client Timeout and Buffer Clearing Broker Errors

For commonly asked questions, please refer to the RPC Broker FAQs on the web at: http://vista.med.va.gov/broker/faqs.html.

How to Debug Your Application Beside the normal debugging facilities provided by Delphi, you can also invoke a debug mode so that you can step through your code on the client side and your RPC code on the M server side simultaneously.

To do this:

1. On the client side, set the DebugMode property on the TRPCBroker component to True. When the TRPCBroker component connects with this property set to True, you will get a dialog window indicating your workstation IP address and the port number.

2. At this point, switch over to the M server, and set any break points in the routines being called in order to help isolate the problem. Then issue the M debug command (e.g., ZDEBUG in DSM).

3. Start the following server process:

>D EN^XWBTCP

You will be prompted for the workstation IP address and the port number. After entering the information, switch over to the client application and click on the OK button of the dialog window.

4. You can now step through the code on your client, and simultaneously step through the code on the server side for any RPCs that your client calls.

Identifying the Listener Process on the Server On DSM systems, where the Broker Listener is running, the Listener process name is RPCB_Port:NNNN, where NNNN is the port number being listened to. This should help quickly locate Listener processes when troubleshooting any connection problems.

Example: RPCB_Port:9200

Identifying the Handler Process on the Server On DSM systems the name of a Handler process is ipXXX.XXX:NNNN, where XXX.XXX are the last two octets of the client IP address and NNNN is the port number.

Example: ip1.205:3504

RPC Error Trapping M errors on the server that occur during RPC execution are trapped by the use of M and Kernel error handling. In addition, the M error message is sent back to the Delphi client. Delphi will raise an exception EBrokerError and a popup box displaying the error. At this point RPC execution terminates and the channel is closed.

In some instances, an application's RPC could get a memory allocation error on the server (in DSM an "allocation failure"). Kernel does not trap these errors. However, these errors are trapped in the operating system's error trap. For example, if an RPC receives or generates an abundance of data in local memory, the symbol table could be depleted resulting in a memory allocation error. To diagnose this problem, users should check the operating system's error trap.

Testing Your RPC Broker Connection To test the RPC Broker connection from your workstation to the M server, use the RPC Broker Diagnostic Program (i.e., RPCTEST.EXE, located in the ..\Broker directory that was installed with the client workstation).

For a complete description of the RPC Broker Diagnostic program, please refer to Chapter 4, "Troubleshooting," in the RPC Broker Systems Manual.

For a demonstration/test using the Broker to connect to a server, please run the BrokerExample.EXE located in the ..\BDK32\Samples\BrokerEx directory.

Memory Leaks A good indication of a memory leak is when a running program is steadily decreasing the free pool of memory. As it runs or every time the program is started and stopped, free memory is steadily decreased.

Specifically, a program requests some bytes of memory from the Windows operating system (OS). When the OS provides it, it marks those bytes as taken. The free pool of memory (i.e., unmarked bytes) is decreased. When the program is finished with the memory, it should return the memory back to the OS by calling the FREE or DISPOSE functions. This allows the OS to clear the "taken" status of that memory, thereby replenishing its free pool. When a programmer forgets to free the memory after use or the program fails before it has a chance to execute the code that frees the memory, the memory is not reclaimed.

At all times, the program should keep track of which memory it's using. It does this by storing "Handles" (i.e., memory addresses of the beginning byte of each memory block). Later, when freeing memory, the Handle is used to indicate which memory address to free. If the variable that holds such a Handle is overwritten, there is no way to determine the Handle.

Nine out of ten times, memory leakage can be traced back to the application code that requests memory and then forgets to return it or cannot clean up after a crash.

As common with other professional-level languages (e.g., C/C++), Delphi has constructs that applications can use to: request memory, type cast it, and return it. This requires developers to use their best judgement on how to best work with the system memory.

Avoiding memory leaks (and the often-subtle coding errors that lead to them) is a challenge for Delphi programmers, especially for those whose main experience is working with M.

The insidious effect of these leaks (e.g., gobbling up 1K of memory each time that a certain event occurs) makes them difficult to detect with normal program testing. By "normal testing" we mean exercising all the possible paths through the code once, a difficult enough process in a Windows environment. Often, these leaks will result in a symptom only under peculiar conditions (e.g., several other applications are running, reducing system resources) or only after extended use of the application (e.g., Do you notice that Windows problems crop up in the afternoon, even though you were doing the same thing that morning?).

The symptom that we are most likely to hear about from users is the following:

"My computer was working fine until I installed the XYZ VISTA package on my PC. Now, it freezes up (gives me error message, says it's out of memory, etc.) all the time, even when I am not using the XYZ package. No, I can't duplicate it, it just happens!"

One of the reasons that there is an extensive market for automated testing tools for Windows and client-server applications is that thorough testing is very difficult to do manually.

Fortunately, there are diagnostic products available for detecting code that will cause memory leaks. It will help programmers and code reviewers to find these leaks. Its use by people just starting out in Delphi programming will help them identify the situations that cause memory leaks. This can serve as a good learning experience for the new Delphi developer.

No application is immune from memory leaks, careful analysis of previous Broker code revealed some places where, under certain conditions, memory was not being released after it was used (i.e., memory leaks). These areas have been identified and corrected with this version of the Broker.

Client Timeout and Buffer Clearing If a remote procedure call fails to successfully complete due to a timeout on the client, the buffer on the server would contain data from the uncompleted call. Without special handling, this buffer on the server would be returned whenever the next RPC was executed.

The solution to this problem is:

1. The new RPCTimeLimit property on the TRPCBroker component on the client helps avoid the problem in the first place.

2. In the event of a cancellation of a Network I/O operation, the Broker state on the client changes from NO FLUSH to FLUSH. When this state change occurs, the next RPC executed undergoes a read operation prior to execution where any leftover incoming buffer is discarded. At the end of this operation, the Broker state on the client will return to NO FLUSH and the RPC will execute normally. While the FLUSH state exists, users may experience a delay while the corrupted RPC data is discarded. The delay will be proportional to the amount of data in the buffer.

Broker Error Messages The following list of errors/messages are Broker-specific and are not Winsock related:


Error/Message Name Number Description Insufficient Heap XWB_NO_HEAP 20001 This is a general error condition indicating insufficient memory. It can occur when an application allocates memory for a variable. This error can occur for some of the following reasons: · Too many open applications · Low physical memory · Small virtual memory swap file (if dynamic, maybe low disk space) · User selecting too many records Resolution: Common solutions to this error include the following: · Close some or all other applications · Install more memory · Increase the swap file size or, if dynamic, leave more free space on disk · Try working with smaller data sets · Reboot the workstation M Error - Use ^XTER XWB_M_REJECT 20002 The server side of the application errored out. The Kernel error trap has recorded the error. Resolution: Examine the Kernel error trap for more information and specific corrective Actions. Signon was not completed XWB_BadSignOn 20004 This error indicates the user did not successfully signon. Resolution: Either the Access and Verify codes were incorrect or the user pressed the Cancel button on the signon window. BrokerConnections list could not be created XWB_BldConnectList 20005 This error is a specific symptom of a low memory condition. Resolution: Please refer to the "Insufficient Heap" error message for a more detailed explanation and corrective measures. RpcVersion cannot be empty XWB_NullRpcVer 20006 This error occurs when an RPC does not have an associated version number. Each RPC must have a version number. Resolution: Contact the developers responsible for the application software to take corrective Action. Remote procedure not registered to application XWB_RpcNotReg 20201 This error indicates the application attempted to execute an RPC that was not, entered into the RPC multiple field in the REMOTE PROCEDURE file (#8994) for this application. Resolution: The developers responsible for the application should be contacted. As a "last resort" corrective measure, you may try to re-index the cross-reference on the RPC field (#.01) in the REMOTE PROCEDURE file (#8994) with the RPC field (#320) of the OPTION file (#19). Ideally, this should only be attempted during off or low system usage.


For common Winsock error messages, please refer to the RPC Broker "FAQ: Common Winsock API Error/Status Messages" on the web at: http://vista.med.va.gov/broker/docs/winsock.html.

Tutorial: Introduction The major functions of a TRPCBroker component in a Delphi application are to: · Connect to an RPC Broker server system from a client. · Execute remote procedure calls (RPCs) on that system. · Return data results from RPC to the client.

This tutorial guides you through using a TRPCBroker component to perform each of these tasks, by having you create a Delphi application, step-by-step. This application will retrieve a list of terminal types from the server, and display information about each terminal type.

After you have completed this tutorial, you should be able to: · Include a TRPCBroker component in a Delphi application. · Retrieve the end-user workstation's designated server and port to connect to. · Establish a connection through the RPC Broker component to an RPC Broker server. · Create M routines that return data in the formats necessary to be called from RPCs. · Create RPCs. · Call RPCs from a Delphi application to retrieve data from VISTA database. · Pass parameters from your Delphi application to RPCs.

Tutorial: Advanced Preparation Namespacing of Routines and RPCs

Each tutorial user should choose a unique namespace beginning with Z, concatenated with two or three other letters, for example ZYXU. Use this namespace as the beginning of the names for all routines and RPCs that you create during this tutorial. Using your namespace protects the system you are using from having existing routines and RPCs overwritten. This namespace is referred to as Zxxx during the tutorial.


Tutorial Prerequisites

To use this tutorial: · You should already have M programming skills, and some familiarity with Delphi. · You must have Delphi and the Broker Development Kit installed on your workstation. · Your workstation must have network access to an M account that is running a Broker server process. · You must have programmer access in this M account, and it should be a test account (not production). Also, you need the XUPROGMODE key assigned to your user account.

Tutorial: Step 1 -- RPC Broker Component The first step of this tutorial is to create a Delphi application that includes a TRPCBroker component.

To do this: 1. In Delphi, create a new application. Delphi will create a blank form, named Form1.

2. Set Form1's Caption property to Terminal Type Display.

3. From the Kernel component palette tab, add a TRPCBroker component to your form. The instance of the component will automatically be named RPCBroker1. It should be renamed to brkrRPCBroker1.

In general the name of the component can be any meaningful name that begins with "brkr" to indicate a TRPCBroker component.

4. Leave the default values for Server and ListenerPort as is (they are retrieved from your workstation's Registry). In the next section of the tutorial, you will add code to retrieve these values at run-time from the workstation's Registry.

5. Set the ClearParameters and ClearResults properties to True if they are not set to True already. This ensures that each time a call to an RPC is made, the Results property is cleared beforehand, and the Param property is cleared afterwards.

Your form should look like:



The next tasks are to use the TRPCBroker component to retrieve the end-user workstation's RPC Broker server and port information (Step 2), and then to establish a connection through the TRPCBroker component to the M server (Step 3).

Tutorial: Step 2 -- Get Server/Port The TRPCBroker component you've added to your form is hard coded to access the Broker server and listener port that it picks up from your own (developer) workstation (by default, BROKERSERVER and 9200). Naturally you don't want this to be the only server and port that your application can connect to. To retrieve the end-user workstation's designated Broker server and port to connect to, as stored in their Registry, you can use the GetServerInfo function.

To retrieve the end-user workstation's designated server and port:

1. Include the RPCConf1 unit in your Pascal file's uses clause. This is the unit that GetServerInfo is a part of.

2. Double-click on a blank region of the form. This creates an event handler procedure, TForm1.FormCreate, in your Pascal source code.

3. Add code to the FormCreate event handler that retrieves the correct server and port to connect to, using the GetServerInfo function. If mrCancel is returned, your code should quit. Otherwise, your code should then set brkrRPCBroker1's Server and ListenerPort properties to the returned values.

The code should look like the following:

procedure TForm1.FormCreate(Sender: TObject); var ServerStr: String;

       PortStr: String;

begin

 // Get the correct port and server from the Registry.
 if GetServerInfo(ServerStr,PortStr)<> mrCancel then
 begin
   brkrRPCBroker1.Server:=ServerStr;
   brkrRPCBroker1.ListenerPort:=StrToInt(PortStr);
 {connectOK}
 end
 else
   Application.Terminate;

end;


Now that you have code to retrieve the appropriate RPC Broker server and listener port, in the next section of the tutorial (Step 3) your application will use the TRPCBroker component to establish a connection to the server.

Tutorial: Step 3 -- Establish Broker Connection Now that your application can determine the appropriate RPC Broker server and port to connect to (Step 2), you can add code to establish a connection to the designated RPC Broker server from your application. The act of establishing a connection leads the user through signon. If signon succeeds, a connection is established.

To establish a connection from your application to a RPC Broker server:

1. Add code to Form1's OnCreate event handler. The code should: a. Set brkrRPCBroker1's Connected property to True (inside of an exception handler try...except block). This will cause an attempt to connect to the RPC Broker server. b. Check if an EBrokerError exception is raised. If this happens, connection failed, and your code should inform the user of this and terminate the application.

The OnCreate event handler should now look like:

procedure TForm1.FormCreate(Sender: TObject); var ServerStr: String;

       PortStr: String;

begin

 // Get the correct port and server from the Registry.
 if GetServerInfo(ServerStr,PortStr)<> mrCancel then
 {connectOK begin}
 begin
   brkrRPCBroker1.Server:=ServerStr;
   brkrRPCBroker1.ListenerPort:=StrToInt(PortStr);
   // Establish a connection to the RPC Broker server.
   try
     brkrRPCBroker1.Connected:=True;
   except
     On EBrokerError do
     {error begin}
     begin
       ShowMessage('Connection to server could not be established!');
       Application.Terminate;
     {error end}
     end;
   {try end}
   end;
 {connectOK end}
 end
 else
   Application.Terminate;

end;

Every call that invokes an RPC Broker server connection should be done in an "exception handler" try...except block, so that EBrokerError exceptions can be trapped.

2. Save, compile and run your application. It should connect to the M server returned by the GetServerInfo function. You may be prompted to sign on with Access and Verify codes (unless Auto Signon is enabled, and you are already signed on). If you can connect successfully, your application will run (at this point, it is just a blank form). Otherwise, troubleshoot your RPC Broker connection until you can get your application to connect.

3. If the server system defined in your Registry is not your development system (the one on which you will create RPCs for this application), update your Registry using the ServerList.EXE program so that your application will connect to the proper M server.

Now that your application can establish a connection to the end-user's server system, you can go about retrieving data from the server system. In the next steps of the tutorial, you will create a custom RPC that retrieves a list of all of the terminal types on the server system, and call that RPC from your application.

Tutorial: Step 4 -- Routine to List Terminal Types Now that your application uses an RPC Broker component to connect correctly to an RPC Broker server (Step 3), you are ready to create custom RPCs that your application can call. For the tutorial, you will create an RPC that retrieves the list of all terminal types from the RPC Broker server.

The first step in creating an RPC is to create the routine that the RPC will execute. You must create its input and output in a defined format that will be compatible with being executed as an RPC.

To do this:

1. Choose the data format that your RPC should return. The type of data that you need to return to your client application determines the format of the routine that your RPC will call. There are five return value types for RPCs: · SINGLE VALUE · ARRAY · WORD PROCESSING · GLOBAL ARRAY · GLOBAL INSTANCE

Since the type of data the tutorial application would like returned is a list of terminal types, and that list could be quite long, use a return value type GLOBAL ARRAY for your RPC. For the routine called by your RPC, this means that: · Your routine should return a list of terminal types in a global. Each terminal type should be on an individual data node, subscripted numerically. · The return value of your routine (always returned in the routine's first parameter) should be the global reference of the data global, in closed root form. The data nodes should be one level descendant from the global reference.

2. Create a routine, in the M account that your TRPCBroker component connects to, that outputs a list of terminal types in the format determined above. The format for each data node that is returned for a terminal type could be anything; for the sake of this application, set each data node to "ien^.01 field" for the terminal type in question. Store each node in ^TMP($J,"ZxxxTT",#).

ZxxxTT  ;ISC-SF/KC TUTORIAL RTN, BRK 1.1; 7/22/97

;;1.0;;

TERMLIST(GLOBREF) ; retrieve list of term types

; return list in ^TMP($J,"ZxxxTT")
; format of returned results: ien^.01 field
N %                             ; scratch variable
K ^TMP($J,"ZxxxTT")             ; clear data return area
D LIST^DIC(3.2)                 ; retrieve list of termtype entries
; now set termtype entries into data global
I '$D(DIERR) D
.S %=0 F  S %=$O(^TMP("DILIST",$J,2,%)) Q:%=""  D
..S ^TMP($J,"ZxxxTT",%)=$G(^TMP("DILIST",$J,2,%))_"^"_$G(^TMP("DILIST",$J,1,%))
K ^TMP("DILIST",$J)               ; clean up
S GLOBREF=$NA(^TMP($J,"ZxxxTT"))   ; set return value
Q

3. Test the routine. Call it like the Broker would:

> D TERMLIST^ZxxxTT(.RESULT)

a. Confirm that the return value is the correct global reference:

> W RESULT

 ^TMP(566363396,"ZxxxTT")

b. Confirm that the data set into the global is in the following format:

^TMP(566347920,"ZxxxTT",1) = 1^C-3101 ^TMP(566347920,"ZxxxTT",2) = 2^C-ADDS ^TMP(566347920,"ZxxxTT",3) = 3^C-ADM3 ^TMP(566347920,"ZxxxTT",4) = 38^C-DATAMEDIA ^TMP(566347920,"ZxxxTT",5) = 106^C-DATATREE ^TMP(566347920,"ZxxxTT",6) = 4^C-DEC ^TMP(566347920,"ZxxxTT",7) = 5^C-DEC132 ^TMP(566347920,"ZxxxTT",8) = 93^C-FALCO ^TMP(566347920,"ZxxxTT",9) = 6^C-H1500 ^TMP(566347920,"ZxxxTT",10) = 103^C-HINQLINK ^TMP(566347920,"ZxxxTT",11) = 132^C-HINQLINK ^TMP(566347920,"ZxxxTT",12) = 63^C-HP110 ^TMP(566347920,"ZxxxTT",13) = 34^C-HP2621

Once you've tested your routine, and confirmed that it returns data correctly, the next step (Step 5) is to create the RPC that will call this routine.

Tutorial: Step 5 -- RPC to List Terminal Types Now that you've created an RPC-compatible routine to list terminal types (Step 4), you can go ahead and create the RPC itself (the entry in the REMOTE PROCEDURE file) that will call the routine.

To create an RPC that uses the TERMLIST^ZxxxTT routine:

1. Using VA FileMan, create a new RPC entry in the REMOTE PROCEDURE file. Set up the RPC as follows:

            NAME: ZxxxTT LIST
             TAG: TERMLIST
         ROUTINE: ZxxxTT

RETURN VALUE TYPE: GLOBAL ARRAY

    WORD WRAP ON: TRUE
     DESCRIPTION: Used in RPC Broker developer tutorial.

The RPC's RETURN VALUE TYPE is set to GLOBAL ARRAY. This means that the RPC expects a return value that is a global reference (with data stored at that global reference).

Also, the RPC's WORD WRAP ON is set to TRUE. This means each data node from the M server is returned as a single node in the Results property of your TRPCBroker component in Delphi. Otherwise, the data would be returned concatenated into a single node in the Results property.


In the next step of the tutorial (Step 6) you will call this RPC from the tutorial application, through its TRPCBroker component.

Tutorial: Step 6 -- Call ZxxxTT LIST RPC Now that you have created and tested the ZxxxTT LIST RPC on the M server system, you can use your Delphi application's TRPCBroker component to call that RPC.

To call the ZxxxTT LIST RPC from your Delphi application to populate a list box:

1. Place a TListBox component on your form. It should be automatically named ListBox1. · Size it so that it uses the full width of the form, and half of the form's height.

2. Place a button beneath ListBox1. · Set its caption to 'Retrieve Terminal Types'. · Size the button so that it is larger than its caption.

3. Double-click on the button. This creates an event handler procedure, TForm1.Button1Click, in your Pascal source code.

4. In the TForm1.Button1Click event handler, add code to call the ZxxxTT LIST RPC and populate the list box with the retrieved list of terminal type entries. This code should: a. Set RCPBroker1's RemoteProcedure property to ZxxxTT LIST. b. Call brkrRPCBroker1's Call method (in a try...except exception handler block) to invoke that RPC. c. Retrieve results from brkrRPCBroker1's Results property, setting them one-by-one into the list box's Items property.

This code should look as follows:

Procedure TForm1.Button1Click(Sender: TObject); var

  i: integer;

begin

 brkrRPCBroker1.RemoteProcedure:='ZxxxTT LIST';
 try
   {call begin}
   begin
     brkrRPCBroker1.Call;
     ListBox1.Clear;
     for i:=0 to (brkrRPCBroker1.Results.Count-1) do
       ListBox1.Items.Add(piece(brkrRPCBroker1.Results[i],'^',2));
   {call end}
   end;
 except
   On EBrokerError do
     ShowMessage('A problem was encountered communicating with the server.');
 {try end}
 end;

end;

5. Include the mfunstr unit in the Uses clause of your project's Pascal source file. This enables your application to use the piece function included in mfunstr.

6. Your user account must have XUPROGMODE key assigned. This allows your application to execute any RPC, without the RPC being registered. Later in the tutorial you will register your RPCs.

7. Now run your application, and press the Retrieve Terminal Types button. It should retrieve and display terminal type entries, and appear as follows:



Now that you can retrieve a list of terminal type entries, the next logical task is to retrieve a particular entry when a user selects that entry in the list box.

Tutorial: Step 7 -- Associating IENs When a user selects a terminal type entry in the list box, a typical Action would be to retrieve the corresponding record and display its fields. The key to retrieving any VA FileMan record is knowing the IEN of the record. Thus, when a user selects an entry in the list box, you need to know the IEN of the corresponding VA FileMan entry. However, the list box items themselves only contain the name of each entry, not the IEN.

The subscripting of items in the list box still matches the original subscripting of items returned in brkrRPCBroker1's Results property, as performed by the following code in Button1Click event handler:

for i:=0 to (brkrRPCBroker1.Results.Count-1) do

 ListBox1.Items.Add(piece(brkrRPCBroker1.Results[i],'^',2));

If no further calls to brkrRPCBroker1 were made, you could simply refer back to brkrRPCBroker1's Results[x] item to obtain the matching IEN of a list boxes' Items[x] item. But, since brkrRPCBroker1 will be used again, the Results property will be cleared. So the results must be saved off in another location, if you want to be able to refer to them after other Broker calls are made.

To save off the Results to another location:

1. Create a variable named TermTypeList, of type TStrings. This is where brkrRPCBroker1.Results will be saved. Create the variable in the section of code where TForm1 is defined as a class:

type

 TForm1 = class(TForm)
   brkrRPCBroker1: TRPCBroker;
   ListBox1: TListBox;
   Button1: TButton;
   procedure FormCreate(Sender: TObject);
   procedure Button1Click(Sender: TObject);
 private
   {Private declarations}
 public
   {Public declarations}

// Added declaration of TermTypeList.

   TermTypeList: TStringList;
 end;

2. In Form1's OnCreate event handler, call the Create method to initialize the TermTypeList. Do this in the first line of code of the event handler: TermTypeList:=TStringList.Create;

3. Create an event handler for Form1's OnDestroy event (select Form1, go to the Events tab of the Object Inspector, and double-click on the right-hand column for the OnDestroy event). In that event handler, add one line of code to call the Free method for TermTypeList. This frees the memory used by the list:

procedure TForm1.FormDestroy(Sender: TObject); begin

 TermTypeList.Free;

end;

4. In Button1's OnClick event handler, add a line of code to populate TermTypeList with the list of terminal types returned in brkrRPCBroker1's Results property. This code will use the Add method of TStrings sequentially so that the subscripting of TermTypeList will match the subscripting of Results. The code for that event handler should then look like:

procedure TForm1.Button1Click(Sender: TObject); var

 i: integer;

begin

 brkrRPCBroker1.RemoteProcedure:='Zxxx LIST';
 try
  {call begin}
   begin
     brkrRPCBroker1.Call;
     for i:=0 to (brkrRPCBroker1.Results.Count-1) do begin {copy begin}
       ListBox1.Items.Add(piece(brkrRPCBroker1.Results[i],'^',2));
       // Added line.
       TermTypeList.Add(brkrRPCBroker1.Results[i]);
     {copy end}
     end;
   {call end}
   end; 
 except
   On EBrokerError do
     ShowMessage('A problem was encountered communicating with the server.');
 {try end}
 end;

end;

5. Then, to determine (and display) the IEN of the corresponding terminal type when a user selects an item in the list box: a. Create an OnClick event handler for ListBox1 by double-clicking on the list box. b. Add code to the new event handler that checks if an item is selected. If an item is selected in the list box, display the first piece of the corresponding item saved off in the TermTypeList array (the index subscripts of TermTypeList and of the list box match each other). This is the IEN of the corresponding VA FileMan entry.

procedure TForm1.ListBox1Click(Sender: TObject); var

 ien: String;

begin

 if (ListBox1.ItemIndex <> -1) then
 {displayitem begin}
 begin
   ien:=piece(TermTypeList[ListBox1.ItemIndex],'^',1);
   ShowMessage(ien);
 {displayitem end}
 end;

end;

6. Compile and run your application. When you click on an item in the list box, the IEN corresponding to that item should be displayed in a pop-up message window.


Now that you can determine the IEN of any entry the user selects in the list box, you can retrieve and display the corresponding VA FileMan record for any selected list box entry.

Tutorial: Step 8 -- Routine to Retrieve Terminal Types Now that you have associated an IEN for each record displayed in the list box (Step 7), you can use that IEN to display fields from any terminal type entry in the list box that a user selects. To retrieve the fields for any selected terminal type entry, you should create a second custom RPC. This RPC will need to take an input parameter, the record IEN, to know which record to retrieve.

To create an RPC routine to retrieve individual terminal type records:

1. Choose the data format that your RPC should return. The type of data that you need to return to your client application determines the format of the routine that your RPC will call. In this case, the RPC should, given an IEN, return fields .01, 1, 2, 3, 4, 6, and 7 (Name, Right Margin, Form Feed, Page Length, Back Space, Open Execute, and Close Execute).

Since this information is constrained and small, a return type of ARRAY would be suitable for this RPC. The return format of the array is arbitrary; for the sake of this application, the routine should return fields .01, 1, 2, 3, and 4 in node 0; field 6 (a 245-character field) in node 1; and field 7 (also a 245-character field) in node 2. This array must be returned in the first parameter to the routine.

2. The routine for this RPC also needs to be able to take an IEN as an input parameter. Any additional input parameters such as one for the IEN must follow the required input parameter in which results are returned.

3. Add a second subroutine to the ZxxxTT routine for the second RPC, similar to the following. This subroutine uses an IEN to retrieve fields for a particular terminal type. It then sets three result nodes, each containing a specified set of fields for the record corresponding to the IEN parameter.

TERMENT(RESULT,IEN) ; retrieve a string of fields for a termtype

; format of results (by field number):
; RESULT(0)=.01^1^2^3^4
; RESULT(1)=6
; RESULT(2)=7
;
N I,ARRAY S IEN=IEN_",",RESULT(1)=""
D GETS^DIQ(3.2,IEN,".01;1;2;3;4;6;7","","ARRAY")
S RESULT(0)="" I '$D(DIERR) D
.F I=.01,1,2,3,4 D
..S RESULT(0)=RESULT(0)_ARRAY(3.2,IEN,I)_"^"
.S RESULT(1)=ARRAY(3.2,IEN,6)
.S RESULT(2)=ARRAY(3.2,IEN,7)
Q

4. Test the routine. Call it like the Broker would:

>D TERMENT^ZxxxTT(.ARRAY,103)

Confirm that the return array contains the specified fields in the following nodes:

ARRAY(0)=C-HINQLINK^80^#,$C(27,91,50,74,27,91,72)^24^$C(8)^ ARRAY(1)=U $I:(0:255::255:512) ARRAY(2)=U $I:(:::::512) C $I


Once you've tested your routine, and confirmed that it returns data correctly, the next step (Step 9) is to create the RPC that will call this routine.

Tutorial: Step 9 -- RPC to Retrieve Terminal Types Now that you've created an RPC-compatible routine to retrieve fields from a terminal type record (Step 8), you can go ahead and create the RPC itself.

To create an RPC that uses the TERMENT^ZxxxTT routine:

1. Using VA FileMan, create a new RPC entry in the REMOTE PROCEDURE file. Set up the RPC as follows:

            NAME: ZxxxTT RETRIEVE
             TAG: TERMENT
         ROUTINE: ZxxxTT

RETURN VALUE TYPE: ARRAY

     DESCRIPTION: Used in RPC Broker tutorial.
 INPUT PARAMETER: IEN    PARAMETER TYPE: LITERAL

The RPC's RETURN VALUE TYPE is set to ARRAY. This means that the RPC expects a return value that contains results nodes, each subscripted only at the first subscript level.

The WORD WRAP ON setting does not affect RPCs whose RETURN VALUE TYPE is ARRAY.

The additional input parameter needed to pass in a record IEN is documented in the INPUT PARAMETER multiple. Its parameter type is LITERAL, which is appropriate when being passed the numeric value of an IEN.


This RPC can now be called from a Delphi application, through the TRPCBroker component.

Tutorial: Step 10 -- Call Zxxx RETRIEVE RPC When a user selects a terminal type entry in the list box, the OnClick event is triggered. The new ZxxxTT RETRIEVE RPC can be called from that OnClick event, as a replacement for the code there that simply displays the IEN of any selected record.

To use the ZxxxTT RETRIEVE RPC to display fields from a selected terminal type:

1. Create labels and edit boxes for each of the fields the RPC returns from the Terminal type file:

Terminal Type Field: Add a TEdit component named: Add a Label with the Caption: .01 Name Name 1 RightMargin Right Margin: 2 FormFeed Form Feed: 3 PageLength Page Length: 4 BackSpace Back Space: 6 OpenExecute Open Execute: 7 CloseExecute Close Execute:

2. Update ListBox1's OnClick event handler. Add code so that when the user clicks on an entry in the list box, your application will call the ZxxxTT RETRIEVE RPC to retrieve fields for the corresponding terminal type, and display those fields in the set of TEdit controls on your form. This code should: a. Set RCPBroker1's RemoteProcedure property to ZxxxTT RETRIEVE. b. Pass the IEN of the selected terminal type to the RPC, using the TRPCBroker's runtime Param property. Pass the IEN in the Value property (i.e., brkrRPCBroker1.Param[0].Value). c. The PType for the IEN parameter should be passed in brkrRPCBroker1.Param[0].PType. Possible types are literal, reference and list. In this case, to pass in an IEN, the appropriate PType is literal. d. Call brkrRPCBroker1's Call method (in a try...except exception handler block) to invoke the ZxxxTT RETRIEVE RPC. e. Set the appropriate pieces from each of the three Results nodes into each of the TEdit boxes corresponding to each returned field. The code for the OnClick event handler should look like the following:

procedure TForm1.ListBox1Click(Sender: TObject); var

 ien: String;

begin

 if (ListBox1.ItemIndex <> -1) then
 {displayitem begin}
 begin
   ien:=piece(TermTypeList[ListBox1.ItemIndex],'^',1);
   brkrRPCBroker1.RemoteProcedure:='ZxxxTT RETRIEVE';
   brkrRPCBroker1.Param[0].Value := ien;
   brkrRPCBroker1.Param[0].PType := literal;
   try
     {call code begin}
     begin
       brkrRPCBroker1.Call;
       Name.Text:=piece(brkrRPCBroker1.Results[0],'^',1);
       RightMargin.Text:=piece(brkrRPCBroker1.Results[0],'^',2);
       FormFeed.Text:=piece(brkrRPCBroker1.Results[0],'^',3);
       PageLength.Text:=piece(brkrRPCBroker1.Results[0],'^',4);
       BackSpace.Text:=piece(brkrRPCBroker1.Results[0],'^',5);
       OpenExecute.Text:=brkrRPCBroker1.Results[1];
       CloseExecute.Text:=brkrRPCBroker1.Results[2];
     {call code end}
     end;
   except
   On EBrokerError do
     ShowMessage('A problem was encountered communicating with the server.');
   {try end}
   end;
 {displayitem end}
 end;

end;

3. Compile and run your application. When you click on an entry in the list box now, the corresponding fields should be retrieved and displayed in the set of edit boxes on your form.



Tutorial: Register RPCs Up until now, it has been assumed that the only user of your application is you, and that you have programmer access and the XUPROGMODE key in the account where your RPCs are accessed.

Under any other circumstance, any RPCs that your application uses must be registered for use by your application on the host system. Registration authorizes the RPC(s) for use by your client based on user privileges.

To register the RPCs used by the tutorial application:

1. Create an option of type "B" (Broker). For example, create an option called ZxxxTT TERMTYPE for the tutorial application.

2. In the "B"-type option's RPC multiple, make one entry for each RPC your application calls. In the case of this tutorial, there should be two entries: one for ZxxxTT LIST and one for ZxxxTT RETRIEVE.

3. Follow the steps in How to Register an RPC to create an application context, using the ZxxxTT TERMTYPE option. Essentially, add a line of code that calls the CreateContext function, and terminates the application if False is returned. The code for Form1's OnCreate event should now look like:

procedure TForm1.FormCreate(Sender: TObject); var ServerStr: String;

       PortStr: String;

begin

 TermTypeList:=TStringList.Create;
 // Get the correct port and server from Registry.
 if GetServerInfo(ServerStr,PortStr)<> mrCancel then
 {connectOK begin}
 begin
   brkrRPCBroker1.Server:=ServerStr;
   brkrRPCBroker1.ListenerPort:=StrToInt(PortStr);
   // Establish a connection to the RPC Broker server.
   try
     brkrRPCBroker1.Connected:=True;
     // Check security.
     if not brkrRPCBroker1.CreateContext('ZxxxTT TERMTYPE') then
       Application.Terminate;
   except
     On EBrokerError do
    {error begin}
     begin
       ShowMessage('Connection to server could not be established!');
       Application.Terminate;
     {error end}
     end;
   {try end}
   end;
 {connectOK end}
 end
 else
   Application.Terminate;

end;

4. Compile and run your application. Try running it both with and without the XUPROGMODE key assigned to yourself. Without XUPROGMODE, you won't be able to run your application unless the ZxxxTT TERMTYPE option is assigned to your menu tree.

Tutorial: FileMan Delphi Components (FMDC) Congratulations! You have now created a sample application that performs entry lookup, and retrieves fields from any record selected by the end-user. You are now ready to create your own Delphi applications using the RPC Broker.

If your application needs to perform database tasks with VA FileMan on a server, you should consider using the FileMan Delphi Components (FMDC). These components automate the major tasks of working with database records through Delphi. Among the functions they provide are: · Automated entry retrieval into a set of controls · Automated online help for database fields · Automated validation of user data entry · Automated filing of changed data · IEN tracking in all controls · Automated DBS error tracking on the Delphi client · Generic lookup dialog · Record locking · Record deletion

If you need to do more than the most simple database tasks in your Delphi applications, the FileMan Delphi Components (FMDC) encapsulate most of the coding needed to retrieve, validate, and file VA FileMan data.

For more information on FileMan Delphi Components (FMDC), please refer to the FMDC web site at: http://vista.med.va.gov/fmdc/index.html

Tutorial Source Code unit tut1;

interface

uses

 Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Trpcb, RPCConf1, StdCtrls, MFunStr;

type

 TForm1 = class(TForm)
   brkrRPCBroker1: TRPCBroker;
   ListBox1: TListBox;
   Button1: TButton;
   Name: TEdit;
   RightMargin: TEdit;
   FormFeed: TEdit;
   OpenExecute: TEdit;
   CloseExecute: TEdit;
   PageLength: TEdit;
   BackSpace: TEdit;
   Label1: TLabel;
   Label2: TLabel;
   Label3: TLabel;
   Label4: TLabel;
   Label5: TLabel;
   Label6: TLabel;
   Label7: TLabel;
   procedure FormCreate(Sender: TObject);
   procedure Button1Click(Sender: TObject);
   procedure ListBox1Click(Sender: TObject);
   procedure FormDestroy(Sender: TObject);
 private
   {Private declarations}
 public
   {Public declarations}
    // Added declaration of TermTypeList.
    TermTypeList: TStrings;
 end;

var

 Form1: TForm1;


implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject); var ServerStr: String;

       PortStr: String;

begin

 TermTypeList:=TStringList.Create;
 // Get the correct port and server from the Registry.
 if GetServerInfo(ServerStr,PortStr)<> mrCancel then
 {connectOK begin}
 begin
   brkrRPCBroker1.Server:=ServerStr;
   brkrRPCBroker1.ListenerPort:=StrToInt(PortStr);
   // Establish a connection to the RPC Broker server.
   try
     brkrRPCBroker1.Connected:=True;
     if not brkrRPCBroker1.CreateContext('ZxxxTT TERMTYPE') then
       Application.Terminate;
   except
     On EBrokerError do
     {error begin}
     begin
       ShowMessage('Connection to server could not be established!');
       Application.Terminate;
     {error end}
     end;
   {try end}
   end;
 {connectOK end}
 end
 else
   Application.Terminate;

end;

procedure TForm1.Button1Click(Sender: TObject); var

 i: integer;
 brkrRPCBroker1.RemoteProcedure:='ZxxxTT LIST';
 try
   {call begin}
   begin
     brkrRPCBroker1.Call;
  for i:=0 to (brkrRPCBroker1.Results.Count-1) do begin {copy begin}
    ListBox1.Items.Add(piece(brkrRPCBroker1.Results[i],'^',2));
    // Added line.
    TermTypeList.Add(brkrRPCBroker1.Results[i]);
  {copy end}
  end;
   {call end}
   end;
 except
   On EBrokerError do
     ShowMessage('A problem was encountered communicating with the server.');
 {try end}

begin

 end;

end;

procedure TForm1.ListBox1Click(Sender: TObject); var

 ien: String;

begin

 if (ListBox1.ItemIndex <> -1) then
 {displayitem begin}
 begin
   ien:=piece(TermTypeList[ListBox1.ItemIndex],'^',1);
   brkrRPCBroker1.RemoteProcedure:='ZxxxTT RETRIEVE';
   brkrRPCBroker1.Param[0].Value := ien;
   brkrRPCBroker1.Param[0].PType := literal;
   try
     {call code begin}
     begin
       brkrRPCBroker1.Call;
       Name.Text:=piece(brkrRPCBroker1.Results[0],'^',1);
       RightMargin.Text:=piece(brkrRPCBroker1.Results[0],'^',2);
       FormFeed.Text:=piece(brkrRPCBroker1.Results[0],'^',3);
       PageLength.Text:=piece(brkrRPCBroker1.Results[0],'^',4);
       BackSpace.Text:=piece(brkrRPCBroker1.Results[0],'^',5);
       OpenExecute.Text:=brkrRPCBroker1.Results[1];
       CloseExecute.Text:=brkrRPCBroker1.Results[2];
     {call code end}
     end;
   except
   On EBrokerError do
     ShowMessage('A problem was encountered communicating with the server.');
   {try end}
   end;
 {displayitem end}
 end;

end;

procedure TForm1.FormDestroy(Sender: TObject); begin

TermTypeList.Free;

end;

end.

RPC Broker Programmer Preferences You can use the RPC Broker Programmer Preferences application (i.e., BrokerProgPref.EXE) to define certain default property values for the TRPCBroker component. When you add a TRPCBroker component to a Delphi application, the settings you define in the Programmer Preferences Editor are used as the default property values.

Click on various parts of the RPC Broker Programmer Preferences screen below for information on that setting.



(If you are visually challenged or unable to access the information available on this client-side image map, please refer to the "Programmer Preferences Dialogue Box Description" topic.)

You may want to make an entry for BrokerProgPref.EXE in Delphi's Tools Menu, to make it easily accessible from within Delphi.

The BrokerProgPref.EXE is located in the ..\BDK32 directory.

ClearParameters

If checked, automatically sets the ClearParameters design-time property of a TRPCBroker component to True when you add one to a form.

ClearResults

If checked, automatically sets the ClearResults design-time property of a TRPCBroker component to True when you add one to a form.

ListenerPort

Sets the ListenerPort design-time property of a TRPCBroker component to the specified value when you add one to a form.

Server

Sets the Server design-time property of a TRPCBroker component to the specified value when you add one to a form.

Connect in Delphi IDE

Enables or disables the connection to the M server from within the Borland Integrated Development Environment (IDE). Disabling this is useful when you are developing in an environment without a connection to an M server, because an attempt is made to connect to the Server (if enabled) when certain TRPCBroker component properties are edited.

Defaults

Pressing Defaults returns the programmer settings to their default values.


Programmer Preferences Dialogue Box Description

The RPC Broker Programmer Preferences application presents a GUI dialogue box that allows developers to set default values for certain RPC Broker component properties and default settings for RPC Broker development. You can set any of the following: · ClearParameters (check box) -- If checked, automatically sets the ClearParameters design-time property of a TRPCBroker component to True when you add one to a form. · ClearResults (check box) -- If checked, automatically sets the ClearResults design-time property to of a TRPCBroker component to True when you add one to a form. · ListenerPort (text box) -- Sets the ListenerPort design-time property of a TRPCBroker component to the specified value when you add one to a form. · Server (text box) -- Sets the Server design-time property of a TRPCBroker component to the specified value when you add one to a form. · Connect in Delphi IDE (check box) -- Enables or disables the connection to the M server from within the Borland Integrated Development Environment (IDE). Disabling this is useful when you are developing in an environment without a connection to an M server, because an attempt is made to connect to the Server (if enabled) when certain TRPCBroker component properties are edited. · Defaults (button) -- Pressing Defaults returns the programmer settings to their default values.

{ewl RoboEx32.dll, WinHelp2000, }